A one-time-code field where a focus ring glides between slots and digits roll in; wrong codes shake, right ones draw a check.
otpone-time codeverification2fainputformpaste
Installation
$npx shadcn@latest add @geturui/otp-input
Usage
usage.tsx
1import { OtpInput } from "@/components/ui/otp-input";
2
3export function VerifyEmail() {
4 return (
5 <OtpInput
6 length={6}
7 groupSize={3}
8 onComplete={async (code) => {
9 const res = await fetch("/api/verify", { method: "POST", body: code });
10 return res.ok; // true → success check, false → shake and clear
11 }}
12 />
13 );
14}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
length | number | 6 | Number of slots. |
value | string | — | Controlled value. Empty slots in the middle are spaces. |
defaultValue | string | "" | Initial value when uncontrolled. |
onChange | (value: string) => void | — | Called on every edit. |
onComplete | (value: string) => boolean | void | Promise<boolean | void> | — | Called when every slot is filled. Return true to show success, false to shake and clear, nothing to leave status alone. |
status | "idle" | "error" | "success" | — | Controlled status; overrides the result of onComplete. |
mode | "numeric" | "alphanumeric" | "numeric" | Characters accepted. Letters are upper-cased. |
groupSize | number | — | Draw a dash after every N slots, e.g. 3 → 123–456. |
disabled | boolean | false | Disable every slot. |
autoFocus | boolean | false | Focus the first slot on mount. |
aria-label | string | "Verification code" | Accessible name for the group. |
className | string | — | Classes for the wrapper. |
Accessibility
- Each slot is a real input labelled “character n of N” inside a labelled group; the first has autocomplete="one-time-code" for SMS autofill.
- Backspace clears and steps back, ← → Home End move between slots, Delete clears in place.
- Pasting a full code fills every slot from the start; partial pastes fill from the focused slot.
- Checking, success and error are announced through a polite live region and aria-invalid; colour is never the only signal.
- Under reduced motion digits fade instead of rolling and the error shake is skipped.