OTP Input
Also called one-time code, verification code, PIN input, 2FA code
A field for a short code, presented as one box per character.
Example
The value behind the boxes
······
The first box carries autocomplete="one-time-code", which is what lets a phone offer the code straight from the message. Every box is labelled in sequence, so a screen reader announces “Digit 3 of 6” rather than a third anonymous text field.
When to use it
- A short fixed-length code is copied from somewhere else — SMS, an authenticator, an email.
- Reading the code back character by character helps, because the user is comparing it to another screen.
- The length is known and small: four to eight characters. Beyond that the boxes stop helping.
When not to
- The value is remembered rather than copied. A password or a passphrase belongs in one field.
- The length varies. Boxes promise an exact count, and a code that might be six or eight characters breaks that promise.
- The code is alphanumeric and case-sensitive. Separate boxes make it harder to see the whole string and check it.
Trade-offs
- Progress is visible at a glance — four of six filled is obvious without counting.
- Character-by-character comparison against the source is easier than scanning one long string.
- Mistakes are localised: one wrong character is one box to fix.
- Every convenience has to be rebuilt by hand: paste, autofill, Backspace, arrow keys, selection.
- Screen reader output is fragmented — six fields announced separately rather than one code.
- Mobile keyboards may reopen between boxes, and the OS autofill suggestion sometimes only targets the first field.
Accessibility
What this pattern needs in order to work for everyone.
- Keyboard
- Paste must fill the whole code from any box, not drop six characters into one. Handle it on paste, spread the characters, and move focus to the end.
- Backspace on an empty box moves to the previous one and clears it. Without that, correcting a typo means clicking.
- Arrow keys move between boxes; typing a character advances automatically, but only forwards — do not steal focus while someone is reviewing.
- Roles and state
- Give the group a name with `<fieldset>` and `<legend>`, or `role="group"` and a label, so “Verification code” is announced before the first box.
- Label each box in sequence — “Digit 1 of 6” — otherwise a screen reader reads six anonymous text fields.
- Set `autocomplete="one-time-code"` and `inputmode="numeric"`. The first unlocks OS-level autofill from SMS; the second brings up the number pad.
- Announce the result, not just the boxes: a polite live region saying “Code complete, verifying” beats silence after the sixth character.
- Focus
- Focus advances on entry and retreats on Backspace, and stays put when the code is complete — jumping straight to a Verify button robs the user of a last look.
In the wild
- Stripe verification — Six boxes with working paste and SMS autofill, and a visible Verify button rather than auto-submit.
- GitHub 2FA — Accepts a pasted code and submits on completion, with the field still editable afterwards.