Input OTP
hc-inputotp は分割型のワンタイムコードフィールドで、shadcn の
InputOTP に相当します。アクセシブルな単一 input アプローチを
使います: 1 つの本物の <input autocomplete="one-time-code"> が
すべての入力・ペースト・SMS 自動入力・選択を受け取り、
installInputOtp がそれを透明にオーバーレイして、おなじみのボックス
群を描画します。スクリーンリーダーが対話するのはラベルつきの 1 つの
入力で、スロットは装飾です。
これにより、よくある「1 桁 1 input」パターンのスクリーンリーダーと ペーストの問題を回避します。
別名: ワンタイムコード入力、認証コード入力。
基本の HTML
Section titled “基本の HTML”<div class="hc-inputotp" data-length="6"> <input class="hc-inputotp__input" type="text" name="otp" inputmode="numeric" autocomplete="one-time-code" aria-label="One-time code"></div>import { installInputOtp } from '@hypermedia-components/core';installInputOtp(); // idempotent; returns an uninstallerゼロ設定の @hypermedia-components/core/behaviors エントリは自動で
インストールします。ビヘイビアは data-length 個のスロットを描画して
maxlength を設定し、省略されていれば inputmode="numeric"、
autocomplete="one-time-code"、type="text" も補います
(number ではなく type="text" — 先頭のゼロとペーストが機能する
ように)。
| 属性 | 用途 |
|---|---|
data-length | スロット数(デフォルト 6)。入力の maxlength も設定します。 |
data-pattern | 許可する文字を CSS 風のクラスで。デフォルト [0-9]。一致しない文字は入力時に取り除かれます。英数字コードには [0-9a-zA-Z] など。 |
data-groups | スロットを視覚的にグループへ分割 — "3-3"("3 3" / "2,2,2" も可)。グループ間に装飾のセパレータが描画されます。グループサイズの合計が data-length に一致しなければ無視。 |
<input> が実際の値とアクセシブルな名前を運びます — 常に
aria-label または <label> を与え、送信すべきなら name も与えて
ください。
グループセパレータ
Section titled “グループセパレータ”data-groups="3-3" は各スロットグループの間にセパレータを描画します —
123-456 のような整形済みコードでよく使われます:
<div class="hc-inputotp" data-length="6" data-groups="3-3"> <input class="hc-inputotp__input" type="text" aria-label="One-time code"></div>セパレータは aria-hidden です(真実の源は入力の値)。グリフを変える
には --hc-inputotp-separator に任意の CSS content 値を設定します
(例: "·"、または素の広い隙間にする "")。
入力の aria-invalid="true"(またはコンテナの data-invalid)が
エラー枠線を描き、入力の disabled がスロットをミュートします。
コンテナの data-variant="success" | "warning" | "error" は、他の
フォームフィールドと同じバリデーション語彙でスロットの枠線を塗り替え
ます。
<div class="hc-inputotp" data-length="4"> <input class="hc-inputotp__input" type="text" aria-label="Code" aria-invalid="true"></div>
<div class="hc-inputotp" data-variant="success" data-length="4"> <input class="hc-inputotp__input" type="text" aria-label="Code (valid)"></div>
<div class="hc-inputotp" data-length="4"> <input class="hc-inputotp__input" type="text" aria-label="Code" disabled value="12"></div>アクティブスロットとキャレット
Section titled “アクティブスロットとキャレット”キャレットのあるスロットは data-active を持ち、点滅するキャレットを
描画します(CSS なので prefers-reduced-motion: reduce を尊重します —
点滅の代わりにキャレットが静止します)。アクティブスロットはキャレットに
追従します: 入力すると次の空きスロットへ進み、矢印キーで値の中を移動
できます。
スロットのクリックでキャレットがそこへ移動し、その位置を編集でき
ます — 入力済みの長さにクランプされるため、末尾より先の空きスロットを
クリックしてもキャレットは末尾に置かれるだけです(隙間は作れません)。
アクティブスロットは data-active で、キャレットの色は
--hc-inputotp-caret-color でスタイルしてください。
どちらもコンテナからバブリングします:
hc:otpchange— 編集のたびにdetail { value, input }。hc:otpcomplete— 同じ detail。値がすべてのスロットを満たしたときに 発火。
otp.addEventListener('hc:otpcomplete', (e) => { verify(e.detail.value);});htmx での利用
Section titled “htmx での利用”コードが揃った瞬間に自動送信します:
<form data-hx-post="/verify" data-hx-trigger="hc:otpcomplete"> <div class="hc-inputotp" data-length="6"> <input class="hc-inputotp__input" type="text" name="code" inputmode="numeric" autocomplete="one-time-code" aria-label="Verification code"> </div></form>値は名前つきの単一 <input> に住んでいるため、普通にシリアライズ
されます — 追加の隠しフィールドは不要です。
Hyperscript
Section titled “Hyperscript”ヘルパーなしで、コードが埋まったらフォームを自動送信します:
<form data-hx-post="/verify"> <div class="hc-inputotp" data-length="6" _="on hc:otpcomplete call closest <form/> then call it.requestSubmit()"> <input class="hc-inputotp__input" type="text" name="code" aria-label="Code"> </div></form>さらなるパターン: Hyperscript → コンポーネントイベントへの反応。
アクセシビリティ
Section titled “アクセシビリティ”- 値を運ぶのはラベルつきの本物の
<input>1 つです。視覚的なスロットはaria-hiddenなので、支援技術は N 個の空のボックスではなく 1 つの フィールドを読み上げます。 autocomplete="one-time-code"により iOS / パスワードマネージャーが SMS コードを提案でき、inputmode="numeric"が数字キーパッドを表示 します。- アクティブスロットの枠線がフォーカスインジケーターを兼ねます。
キャレットの点滅は
prefers-reduced-motion: reduceを尊重します。 スロットのクリックでキャレットがそこへ移動して編集できます。
テーマ用トークン
Section titled “テーマ用トークン”| トークンパス | 用途 |
|---|---|
inputotp.gap | スロット間のスペース。 |
inputotp.slot-size | スロットのボックスサイズ(正方形)。 |
inputotp.radius / border / bg / fg | スロットのクローム。 |
inputotp.font-size / font-weight | 数字。 |
inputotp.active-border / caret-color | アクティブスロット + キャレット(data-color に追従)。 |
inputotp.error-border | aria-invalid / data-variant="error" の枠線。 |
inputotp.success-border / warning-border | data-variant="success" / "warning" の枠線。 |
inputotp.disabled-bg / disabled-fg | 無効なスロット。 |
CSS 変数
Section titled “CSS 変数”生成される CSS 変数を表示
--hc-inputotp-gap | -slot-size | -radius | -border | -bg | -fg--hc-inputotp-font-size | -font-weight--hc-inputotp-active-border | -caret-color--hc-inputotp-error-border | -success-border | -warning-border--hc-inputotp-disabled-bg | -disabled-fg--hc-inputotp-separator /* the data-groups separator glyph; default "–" */RTL の微調整は先送りです。スロットクリックによるキャレット配置 (アクティブスロットとキャレットを 参照)とグループセパレータ (グループセパレータを参照)はサポート済みです。