OTP Input
betaA one-time-code field drawn as a row of animated slots, with a caret that slides between them and success and error verdicts — paste, SMS autofill, masking and grouping included.
- Forms
- 1 file
- 1 npm package
- Accessibility notes
pnpm dlx @dowel-ui/cli add otp-inputnpm packages installed: class-variance-authority.
import { OtpInput } from "@/components/ui/otp-input";Default
Gallery
In Form
Options
Status
Status States
<OtpInput>
| Prop | Type | Default |
|---|---|---|
allowCharacters accepted; anything else typed or pasted is dropped. | OtpInputAllow | "numeric" |
defaultValueInitial value when uncontrolled. | string | "" |
entranceHow a character arrives in its slot: | "flip" | "roll" | "flip" |
groupsSlot counts per group, e.g. | number[] | — |
lengthNumber of characters in the code. | number | 6 |
maskPaints each filled slot with a dot, or the given character, instead of its value. | boolean | string | false |
onCompleteCalled once each time the last slot is filled. | (value: string) => void | — |
onValueChangeCalled with the sanitised code whenever it changes. | (value: string) => void | — |
separatorDrawn between groups. Decorative. | ReactNode | — |
slotClassNameClasses for each painted slot. | string | — |
slotSize | "sm" | "md" | "lg" | "xl" | "md" |
statusThe verdict on the code. "success" traces a ring around each slot in turn; "error" rings them red, shakes the row once and sets aria-invalid. | OtpInputStatus | "idle" |
statusMessageAnnounced politely while | string | — |
valueControlled value. | string | — |
Plus every attribute of <input> except value, defaultValue, onChange, type, maxLength, size, children.
8/8
checks passed
- Tested — passes
- axe assertion — passes
- Keyboard tested — does not apply
- Storybook examples — passes
- Accessibility documented — passes
- Semantic tokens only — passes
- Motion from tokens — passes
- className merged — passes
- Visible focus — does not apply
- No fixed widths — passes