InputOTP
One-time codes with paste, autofill, errors and an easy way to recover.
Base UI reference ↗Installation
Run it from the root of a project already set up with zunoui init.
npx zunoui@latest add input-otpDependencies
What add input-otp installs alongside the component. The CLI skips any you already have in a compatible version.
ZUNO registry
@zuno/utils
npm
@base-ui/[email protected]
Examples
3 examples · 1 componentVerification code
Six digits in two groups; completion is announced with role="status".
Recovery code
Letters and numbers, upper-cased as you type.
Check your inbox for a 6-digit code.
Error and recovery
A wrong code marks every slot, explains the error and offers to resend. Try 123456.
API reference
Keeps the props, events and refs of the matching Base UI primitive, plus ZUNO's styles.
| Prop | Type | Default |
|---|---|---|
lengthNumber of characters (required). | number | — |
groupsSlots per visual group, e.g. [3, 3]; the separator is decorative. | number[] | [length] |
value / defaultValue / onValueChangeThe whole code as one string. | string | — |
onValueCompleteFires once every slot is filled, to verify or submit. | (value: string) => void | — |
validationTypeWhich characters are accepted; others are ignored, also on paste. | "numeric" | "alpha" | "alphanumeric" | "none" | "numeric" |
normalizeValueTransform input, e.g. toUpperCase for recovery codes. | (value) => string | — |
maskHides characters like a password. | boolean | false |
invalid / describedByError state on every slot and the id of the help or error text. | boolean / string | — |
autoCompleteLets the OS offer the code from SMS or email. | string | "one-time-code" |
States
The states that apply to this component and their visual treatment.
| State | Treatment |
|---|---|
| Empty | Six bordered slots; the first takes focus. |
| Typing | Focus advances slot by slot; the value is one string. |
| Complete | onValueComplete fires with the full code. |
| Invalid | Destructive borders plus a linked error message. |
| Disabled | Dimmed slots; not focusable. |
Accessibility
Label the field with a Label pointing at the root id: it names the first slot; the others are named "Character 2 of 6" and so on.
Paste fills every slot at once and SMS autofill works through autoComplete="one-time-code"; Backspace, arrow keys, Home and End move across slots, and only one slot is in the Tab order.
Show errors in text linked with describedBy and set invalid: the border alone is not the only signal.
Offer a way to recover (resend or another method) next to the field instead of trapping the user on a wrong code.