Webパーツ辞典

ワンタイムコード入力One-time code input

SMS やメールで届いた6桁ほどの数字を入れる欄。1桁ずつ四角い枠が並んだ見た目にすることが多い。ログインや登録の本人確認で使う。

表示例

SMS で届いた6桁の数字

別名・英語表記

  • 認証コード入力
  • OTP入力
  • 確認コード入力
  • ワンタイムパスワード入力
  • 2段階認証の入力欄
  • SMS認証コードの欄
  • One-time code input

実装例

<div class="x-otp-input">
  <label class="x-otp-input__l" for="x-otp-input-i">確認コード</label>
  <p class="x-otp-input__h" id="x-otp-input-h">SMS で届いた6桁の数字</p>
  <!-- 入力欄は1つ。6つの枠は後ろに敷いた飾りで、読み上げからは外す。
       欄を6つに分けないので、貼り付けと自動入力がそのまま全桁に入る -->
  <div class="x-otp-input__f">
    <span class="x-otp-input__bs" aria-hidden="true">
      <span class="x-otp-input__b"></span><span class="x-otp-input__b"></span><span class="x-otp-input__b"></span>
      <span class="x-otp-input__b"></span><span class="x-otp-input__b"></span><span class="x-otp-input__b"></span>
    </span>
    <input class="x-otp-input__i" id="x-otp-input-i" type="text" name="code" value="4829"
           inputmode="numeric" autocomplete="one-time-code" spellcheck="false"
           aria-describedby="x-otp-input-h">
  </div>
  <button class="x-otp-input__re" type="button">コードを再送する</button>
</div>

AIへの指示文

「ワンタイムコード入力(One-time code input)」を実装してください。

## これは何か
SMS やメールで届いた6桁ほどの数字を入れる欄。1桁ずつ四角い枠が並んだ見た目にすることが多い。ログインや登録の本人確認で使う。

## 使いどころ
- SMS・メール・認証アプリで届いた確認コードを入れてもらうとき
- 2段階認証のログインや、電話番号・メールアドレスの確認

## 実装の要件
- label + 補足文 + input[type=text][inputmode=numeric][autocomplete=one-time-code][maxlength=6]。後ろに aria-hidden の枠6つを敷く
- 枠と入力欄を同じ等幅の書体にし、幅と字間を ch で決めると、書体が変わっても桁と枠がずれない
- maxlength="6" を付けると、空白やハイフンを含むコードを貼ったときにブラウザが末尾を切り詰める。paste イベントで数字だけ取り出してから入れるか、maxlength を付けずに送信時に桁数を確かめる
- 枠を6つの input に分けると、フォーカスの自動移動・Backspace での戻り・貼り付けの振り分け・自動入力をすべて自前で作ることになり、どれかが壊れやすい。入力欄は1つにして、枠は見た目だけで描くほうが確実(GOV.UK Design System も1つの欄を使う)
- 欄を分けた場合、枠ごとに「6桁中1桁目」のような名前が要り、読み上げでは欄が6つ続く
- type="number" にしない。先頭の 0 が消え、スクロールや上下キーで値が増減する。type="text" に inputmode="numeric" を付ける
- コピーしたときに混ざる空白やハイフンは受け止めて取り除く。桁数が合わないときは「あと2桁足りません」のように何が違うかを伝える
- 有効期限と再送の手段をそばに置く。届かない人がそこで行き詰まる

## アクセシビリティの要件
- 欄全体に見える label を1つ付ける(「確認コード」)。何桁で、どこに届いたかは補足文にして aria-describedby で結ぶ
- autocomplete="one-time-code" を付ける。Safari などは SMS やメールで届いたコードを入力候補に出し、1回で全桁が入る
- 枠の飾りは aria-hidden="true" にして読み上げから外す。読むのは input の値だけにする
- 6桁そろったら自動で送信するなら、その動きを入力の前に文言で予告する(WCAG 3.2.2)
- WCAG 2.2 の 3.3.8 アクセシブルな認証(最低限)に沿い、貼り付けと自動入力を妨げない

## 参考にする実装
この形を出発点にして、プロジェクトの命名規則・色・余白に合わせて調整してください。

```html
<div class="x-otp-input">
  <label class="x-otp-input__l" for="x-otp-input-i">確認コード</label>
  <p class="x-otp-input__h" id="x-otp-input-h">SMS で届いた6桁の数字</p>
  <!-- 入力欄は1つ。6つの枠は後ろに敷いた飾りで、読み上げからは外す。
       欄を6つに分けないので、貼り付けと自動入力がそのまま全桁に入る -->
  <div class="x-otp-input__f">
    <span class="x-otp-input__bs" aria-hidden="true">
      <span class="x-otp-input__b"></span><span class="x-otp-input__b"></span><span class="x-otp-input__b"></span>
      <span class="x-otp-input__b"></span><span class="x-otp-input__b"></span><span class="x-otp-input__b"></span>
    </span>
    <input class="x-otp-input__i" id="x-otp-input-i" type="text" name="code" value="4829"
           inputmode="numeric" autocomplete="one-time-code" spellcheck="false"
           aria-describedby="x-otp-input-h">
  </div>
  <button class="x-otp-input__re" type="button">コードを再送する</button>
</div>
```

```css
/* 貼った先のリセットに頼らないよう、この部品の中だけ border-box にする */
.x-otp-input,
.x-otp-input *:not([class*="fa-"]),
.x-otp-input *:not([class*="fa-"])::before,
.x-otp-input *:not([class*="fa-"])::after {
  box-sizing: border-box;
  /* 貼った先の既定の書体に引きずられないようにする。書体が変わると
     文字の幅と高さが変わり、枠のサイズまでずれる */
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Hiragino Sans", "Noto Sans JP", "Yu Gothic UI", Meiryo, sans-serif;
}

.x-otp-input {
  width: 260px;
  color: #1b2028;
}
.x-otp-input__l {
  display: block;
  font-size: 12px;
  font-weight: 700;
}
.x-otp-input__h {
  margin: 2px 0 8px;
  color: #5b6472;
  font-size: 11px;
}
/* 枠と入力欄は同じ等幅の書体・大きさにし、幅を ch で測る。
   書体が何に落ちても、1文字の幅と枠の幅が同じ単位で決まるので桁と枠がずれない */
.x-otp-input .x-otp-input__f,
.x-otp-input .x-otp-input__b,
.x-otp-input .x-otp-input__i {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  font-size: 22px;
}
.x-otp-input__f {
  position: relative;
  width: 18ch;
  height: 46px;
  overflow: hidden;
  border-radius: 6px;
}
.x-otp-input__bs {
  display: flex;
  height: 100%;
}
.x-otp-input__b {
  width: calc(3ch - 8px);
  height: 100%;
  margin: 0 4px;
  border: 1px solid #7f8a99;
  border-radius: 6px;
  background: #fff;
}
/* 1桁ぶんの幅 3ch = 文字 1ch + 字間 2ch。左に 1ch 空けて文字を枠の中央に置く。
   6桁目のあとのキャレットで横にスクロールしないよう、欄は1枠ぶん広くして外側で切る */
.x-otp-input__i {
  position: absolute;
  top: 0;
  left: 0;
  width: 21ch;
  height: 100%;
  padding: 0 0 0 1ch;
  border: 0;
  outline: none;
  background: none;
  color: #1b2028;
  letter-spacing: 2ch;
  font-variant-numeric: tabular-nums;
}
.x-otp-input__f:focus-within {
  outline: 2px solid #1d4ed8;
  outline-offset: 2px;
}
.x-otp-input__f:focus-within .x-otp-input__b {
  border-color: #1d4ed8;
}
.x-otp-input__re {
  margin-top: 10px;
  padding: 4px 0;
  border: 0;
  background: none;
  color: #1d4ed8;
  font-size: 12px;
  text-decoration: underline;
  cursor: pointer;
}
.x-otp-input__re:focus-visible {
  outline: 2px solid #1d4ed8;
  outline-offset: 2px;
}
```

## 出力の約束
- HTML と CSS を分けて出す。JavaScript が要るときは素の JavaScript で書き、UIフレームワークは使わない。
- 参考実装がアイコンに Font Awesome のクラスを使っている場合は、プロジェクトで使っているアイコンかインライン SVG に置き換えてよい。
- 上のアクセシビリティ要件を満たす。満たせない箇所があるときは、理由を添えて先に知らせる。
- 色・角丸・余白は既存のデザイントークンがあればそれを使う。無ければ CSS 変数として切り出す。

使いどころ

  • SMS・メール・認証アプリで届いた確認コードを入れてもらうとき
  • 2段階認証のログインや、電話番号・メールアドレスの確認

注意点

  • 枠を6つの input に分けると、フォーカスの自動移動・Backspace での戻り・貼り付けの振り分け・自動入力をすべて自前で作ることになり、どれかが壊れやすい。入力欄は1つにして、枠は見た目だけで描くほうが確実(GOV.UK Design System も1つの欄を使う)
  • 欄を分けた場合、枠ごとに「6桁中1桁目」のような名前が要り、読み上げでは欄が6つ続く
  • type="number" にしない。先頭の 0 が消え、スクロールや上下キーで値が増減する。type="text" に inputmode="numeric" を付ける
  • コピーしたときに混ざる空白やハイフンは受け止めて取り除く。桁数が合わないときは「あと2桁足りません」のように何が違うかを伝える
  • 有効期限と再送の手段をそばに置く。届かない人がそこで行き詰まる

アクセシビリティの要点

  • 欄全体に見える label を1つ付ける(「確認コード」)。何桁で、どこに届いたかは補足文にして aria-describedby で結ぶ
  • autocomplete="one-time-code" を付ける。Safari などは SMS やメールで届いたコードを入力候補に出し、1回で全桁が入る
  • 枠の飾りは aria-hidden="true" にして読み上げから外す。読むのは input の値だけにする
  • 6桁そろったら自動で送信するなら、その動きを入力の前に文言で予告する(WCAG 3.2.2)
  • WCAG 2.2 の 3.3.8 アクセシブルな認証(最低限)に沿い、貼り付けと自動入力を妨げない

作るときに使えるツール

関連するパーツ