CODE INPUT: Single-digit-per-cell verification code entry
VARIANTS: Blank | Invalid error | Disabled | 4-cell
COMPOSES: .form-control (each cell is a real form-control input)
Typing a digit auto-advances to the next cell; Backspace on an empty cell moves back
and clears the previous digit. Pasting a full code (on any cell) distributes it across
the row starting from cell 1. A hidden input keeps the joined digits in sync for form
submission. Requires data-controller="code-input".
Default state: 6 cells split 3+3 by .code-input-sep. Each
cell is labelled "Digit N"; the group itself is labelled by the visible field label via
aria-labelledby. The first cell carries autocomplete="one-time-code"
so browsers/password managers can offer SMS-code autofill.
We've emailed a 6-digit code to a.okafor@…. Enter it below to verify your account.
<div class="code-input" role="group" aria-labelledby="…"><input class="form-control code-input-cell" inputmode="numeric" maxlength="1" autocomplete="one-time-code" aria-label="Digit 1" data-code-input-target="cell" data-action="input->code-input#input keydown->code-input#keydown paste->code-input#paste focus->code-input#selectOnFocus">…<span class="code-input-sep" aria-hidden="true">–</span>…<input type="hidden" data-code-input-target="value"></div>
Error state: each cell carries .is-invalid (reusing
.form-control.is-invalid's red border/focus ring — no bespoke error CSS
needed), aria-invalid="true", and aria-describedby pointing at
the error text below the row. Editing any cell clears .is-invalid and
aria-invalid from every cell and hides the error text (C08 — the error
clears on the first correcting keystroke, not on resubmit).
That code isn't valid. Check your email for the latest code and try again.
<input class="form-control code-input-cell is-invalid" aria-describedby="code-input-error" aria-invalid="true" …> … <p class="invalid-feedback" id="code-input-error" data-code-input-target="error">That code isn't valid.</p>
Disabled: real [disabled] attribute on every cell — for an
already-verified code that's now locked from editing.
Your account is already verified.
Any cell count: the controller reads whatever data-code-input-target="cell"
elements are present — no config value for cell count. Drop 4 cells (a PIN) or 6
(an OTP) and it just works.
Use the 4-digit PIN sent to your registered mobile number.
<div class="code-input" role="group" aria-labelledby="…"><!-- 4 cells, no .code-input-sep --></div>