OTP入力 OTP Input

ワンタイムパスワード(認証コード)を一文字ずつ入力するフォーム。

使用場面: 二要素認証・SMS認証コード入力・メール確認コードなどの場面 採用例: Google, LINE

ライブデモ

-
6桁の数字を入力してください

ソースコード

<div class="demo-otp">
  <label class="demo-otp-label">認証コードを入力</label>
  <div class="demo-otp-fields">
    <input class="demo-otp-digit" type="text" maxlength="1" inputmode="numeric" pattern="[0-9]" aria-label="1桁目" />
    <input class="demo-otp-digit" type="text" maxlength="1" inputmode="numeric" pattern="[0-9]" aria-label="2桁目" />
    <input class="demo-otp-digit" type="text" maxlength="1" inputmode="numeric" pattern="[0-9]" aria-label="3桁目" />
    <span class="demo-otp-separator">-</span>
    <input class="demo-otp-digit" type="text" maxlength="1" inputmode="numeric" pattern="[0-9]" aria-label="4桁目" />
    <input class="demo-otp-digit" type="text" maxlength="1" inputmode="numeric" pattern="[0-9]" aria-label="5桁目" />
    <input class="demo-otp-digit" type="text" maxlength="1" inputmode="numeric" pattern="[0-9]" aria-label="6桁目" />
  </div>
  <div class="demo-otp-hint">6桁の数字を入力してください</div>
  <div class="demo-otp-status"></div>
</div>
.demo-otp { text-align: center; max-width: 320px; margin: 0 auto; }
.demo-otp-label { display: block; font-size: 14px; font-weight: 600; color: #333; margin-bottom: 12px; }
.demo-otp-fields { display: flex; gap: 8px; justify-content: center; align-items: center; }
.demo-otp-digit {
  width: 44px; height: 52px; text-align: center; font-size: 20px; font-weight: 700;
  border: 2px solid #d1d5db; border-radius: 10px; outline: none;
  transition: border-color 0.2s, box-shadow 0.2s; color: #333;
}
.demo-otp-digit:focus {
  border-color: var(--ui-primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ui-primary) 20%, transparent);
}
.demo-otp-digit.filled { border-color: var(--ui-primary); color: var(--ui-primary); }
.demo-otp-separator { font-size: 20px; color: #9ca3af; font-weight: 300; }
.demo-otp-hint { font-size: 12px; color: #6b7280; margin-top: 10px; }
.demo-otp-status {
  margin-top: 12px; font-size: 13px; font-weight: 600; min-height: 20px;
}
.demo-otp-status.success { color: var(--ui-primary); }
.demo-otp-status.error { color: #ef4444; }
@keyframes demo-otp-shake { 0%,100%{transform:translateX(0)} 25%{transform:translateX(-6px)} 75%{transform:translateX(6px)} }
.demo-otp-fields.shake { animation: demo-otp-shake 0.3s ease; }
(function(){
  var digits = document.querySelectorAll('.demo-otp-digit');
  var status = document.querySelector('.demo-otp-status');
  var fields = document.querySelector('.demo-otp-fields');
  digits.forEach(function(d, i) {
    d.addEventListener('input', function() {
      this.value = this.value.replace(/[^0-9]/g, '');
      if (this.value) {
        this.classList.add('filled');
        if (i < digits.length - 1) digits[i + 1].focus();
        checkComplete();
      }
    });
    d.addEventListener('keydown', function(e) {
      if (e.key === 'Backspace' && !this.value && i > 0) {
        digits[i - 1].focus(); digits[i - 1].value = ''; digits[i - 1].classList.remove('filled');
      }
    });
    d.addEventListener('paste', function(e) {
      e.preventDefault();
      var text = (e.clipboardData || window.clipboardData).getData('text').replace(/[^0-9]/g, '');
      for (var j = 0; j < Math.min(text.length, digits.length); j++) {
        digits[j].value = text[j]; digits[j].classList.add('filled');
      }
      if (text.length >= digits.length) digits[digits.length - 1].focus();
      else if (text.length > 0) digits[text.length].focus();
      checkComplete();
    });
  });
  function checkComplete() {
    var code = Array.from(digits).map(function(d){ return d.value; }).join('');
    if (code.length === 6) {
      if (code === '123456') {
        status.textContent = '認証成功!'; status.className = 'demo-otp-status success';
      } else {
        status.textContent = 'コードが正しくありません'; status.className = 'demo-otp-status error';
        fields.classList.add('shake');
        setTimeout(function(){ fields.classList.remove('shake'); }, 400);
      }
    } else { status.textContent = ''; status.className = 'demo-otp-status'; }
  }
})();

AIプロンプト

Basic
OTP入力フォームをHTML/CSS/JSで作ってください。6桁の数字を一文字ずつ入力するフィールドです。
Custom
以下の仕様でOTP入力を実装してください。
- 6桁のワンタイムパスワード入力
- 自動フォーカス移動(入力後に次のフィールドへ)
- プライマリカラー: #2563eb
- Backspaceで前のフィールドに戻る
- ペースト対応(コピーしたコードを一括入力)
- 入力完了時の自動検証
- エラー時のシェイクアニメーション
Advanced
アクセシビリティ対応のOTP入力を実装してください。
- 各フィールドに適切な aria-label(「n桁目」)
- inputmode="numeric" でモバイルの数字キーボード表示
- autocomplete="one-time-code" でSMS自動入力対応
- フォーカス管理の完全なキーボードナビゲーション
- スクリーンリーダーで入力状態を通知
- タイマー表示(コード有効期限のカウントダウン)
- 再送信ボタンのクールダウン制御
- prefers-reduced-motion でアニメーション無効化