Forms
OTP input
One box per digit for verification codes, with auto-advance, backspace to go back, arrow key movement and paste to fill every slot.
- Source
- src/components/ui/otp-input.tsx
- Figma
- OTPInput · state (empty, filled, focus, error)
Usage
Included in the GliaKit boilerplate. Import it where you need it:
tsx
import { OTPInput } from "@/components/ui/otp-input";When to use
- Two-factor and email or SMS verification steps.
- Short numeric PINs where each digit should be visible as it is typed.
- For codes with letters, use a regular Input: OTPInput strips every non-digit.
- For passwords, use Input with type="password".
Examples
Error state
Validate in onComplete and pass invalid. Try any code other than 123456.
Disabled
Disable every slot, for example while the code is being checked.
Verification step
A 4-digit code with a verify button that unlocks once every slot is filled.
API reference
OTPInput
Works controlled (value + onChange) or uncontrolled. Does not spread native props.
| Prop | Type | Default | Description |
|---|---|---|---|
| length | number | 6 | Number of digit slots. |
| value | string | - | Controlled value. Omit to let the component hold its own state. |
| onChange | (value: string) => void | - | Called with the digits-only code on every change. |
| onComplete | (value: string) => void | - | Called whenever a change leaves every slot filled. |
| invalid | boolean | - | Error style on every slot, and aria-invalid on each input. |
| disabled | boolean | - | Disables every slot. |
| autoFocus | boolean | - | Focuses the first slot on mount. |
| className | string | - | Classes for the row of slots. |
| aria-label | string | "Verification code" | Accessible name for the group. |
Accessibility
- The slots sit in a role="group" named by aria-label ("Verification code" by default); each slot is labeled "Digit 1", "Digit 2" and so on.
- The first slot has autoComplete="one-time-code", so iOS and Android can offer the code from an SMS.
- inputMode="numeric" opens the number keypad on mobile.
- Arrow keys move between slots, Backspace clears and steps back, and focusing a slot selects its digit.
- When invalid, every slot gets aria-invalid. Show the reason in visible text next to the input.