OTP Input
介绍
六格验证码:输入自动跳格、退格回退、整段粘贴自动分配。填满后校验,错误抖动,正确变绿。
纯 HTML、CSS 与少量原生 JS,没有框架依赖。复制提示词交给 Claude Code、Cursor、Trae 或 Codex,模型会把 OTP Input 加进你的项目并换成你的配色。
适用场景
搜索框、AI 对话输入框、表单字段、文件上传和验证码等用户输入的地方。
安装
订阅 Builder 后,用 8pt CLI 装进项目,或在已接入 8pt MCP 的编辑器里直接调用。
$ npm i -g @8pt-dev/cli && 8pt add otp-input
mcp › 使用 8pt MCP 调用 get_component("otp-input")
代码
OTP Input 的源码,动效只用 transform 与 opacity,并尊重减少动态效果设置。
<form class="x-otp" autocomplete="one-time-code">
<b>输入验证码</b>
<small>已发送到 a•••@example.com · 示例码 246810</small>
<div class="x-otp__row">
<input inputmode="numeric" maxlength="1" aria-label="第 1 位"><input inputmode="numeric" maxlength="1" aria-label="第 2 位"><input inputmode="numeric" maxlength="1" aria-label="第 3 位"><span aria-hidden="true">–</span><input inputmode="numeric" maxlength="1" aria-label="第 4 位"><input inputmode="numeric" maxlength="1" aria-label="第 5 位"><input inputmode="numeric" maxlength="1" aria-label="第 6 位">
</div>
<p class="x-otp__msg" aria-live="polite"></p>
</form>.x-otp{display:grid;justify-items:center;gap:8px;color:var(--d-fg,#fff);text-align:center}
.x-otp b{font:650 16px/1.2 var(--d-font,system-ui,sans-serif)}
.x-otp small{font:12px/1.3 var(--d-font,system-ui,sans-serif);color:var(--d-muted,#9b9ba8)}
.x-otp__row{display:flex;align-items:center;gap:6px;margin-top:8px}
.x-otp__row span{color:var(--d-muted,#9b9ba8)}
.x-otp input{width:38px;height:46px;padding:0;border-radius:10px;border:1.5px solid var(--d-line,rgba(255,255,255,.16));background:var(--d-card,#14141c);color:inherit;font:700 20px/1 ui-monospace,monospace;text-align:center;outline:0;caret-color:var(--d-accent,#4D74FF);transition:border-color .2s,transform .2s}
.x-otp input:focus{border-color:var(--d-accent,#4D74FF);transform:translateY(-2px)}
.x-otp input.fill{border-color:color-mix(in srgb,var(--d-fg,#fff) 40%,transparent)}
.x-otp.ok input{border-color:#3dd68c;color:#3dd68c}
.x-otp.bad .x-otp__row{animation:x-otp-shake .4s}
.x-otp.bad input{border-color:#ff6b6b}
@keyframes x-otp-shake{20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}
…const init = (root) => {
const form = root.querySelector('.x-otp'), ins = [...form.querySelectorAll('input')], msg = form.querySelector('.x-otp__msg');
const CODE = '246810';
let t;
const check = () => { const v = ins.map(i => i.value).join(''); form.classList.remove('ok', 'bad');
if (v.length < 6) { msg.textContent = ''; return; }
void form.offsetWidth;
if (v === CODE) { form.classList.add('ok'); msg.textContent = '✓ 验证成功'; }
else { form.classList.add('bad'); msg.textContent = '验证码不正确'; clearTimeout(t); t = setTimeout(() => { ins.forEach(i => { i.value = ''; i.classList.remove('fill'); }); form.classList.remove('bad'); msg.textContent = ''; ins[0].focus(); }, 900); } };
ins.forEach((inp, i) => {
inp.addEventListener('input', () => { inp.value = inp.value.replace(/\D/g, '').slice(-1); inp.classList.toggle('fill', !!inp.value); if (inp.value && ins[i + 1]) ins[i + 1].focus(); check(); });
inp.addEventListener('keydown', e => { if (e.key === 'Backspace' && !inp.value && ins[i - 1]) { ins[i - 1].focus(); ins[i - 1].value = ''; ins[i - 1].classList.remove('fill'); check(); }
…订阅 Builder 查看完整源码。查看价格