Input OTP
Separate boxes for a one-time code, such as two-factor sign-in.
When to use
- A short one-time code of known length: a sign-in code, a verification code sent by email or SMS.
When not to use
- A password, an API key or any value of variable length: use Input.
- A code longer than about eight characters: use Input with
autoComplete="one-time-code".
Install
npx shadcn@latest add @clinia/input-otpAnatomy
4
8
2
- 1Group
data-slot="input-otp-group"rounded-lg - 2Box
data-slot="input-otp-slot"border-input · size-9 - 3Separator
data-slot="input-otp-separator"size-4
Clinia rules
- Each box has an
inputborder; the active box shows the Trust ring. - Split a six-digit code into two groups of three with
InputOTPSeparator, so it's easier to read and check. - Say where the code was sent right above the boxes, and how to get a new one below them.
Do and don't
Enter the code sent to j•••@clinic.ca.
States
empty
filled
4
8
2
1
invalid
4
8
disabled
focus · active box
4
Focus cells apply the component's focus-visible classes statically. Toggle the site theme to review both themes.
Accessibility
Built in
- The boxes are one input to assistive technology. Pasting a full code fills every box.
- It's one real input behind the boxes: typing fills the next box, Backspace clears the previous one, and the arrow keys move the caret.
Your responsibility
- Give the group an
aria-label, such asVerification code: a screen reader announces it as the field's name. - Set
inputMode="numeric"for digit-only codes and keepautoComplete="one-time-code"so phones offer the code from the message. - On a wrong code, set
aria-invalidand show aFieldErrorthat says what to do next, such as request a new code. - Don't submit the moment the last box fills if the user can't review or correct the code first.
How to test
- Press Tab into the code: the first empty box shows the Trust ring and a caret.
- Type the digits: each box fills in turn. Press Backspace: the last digit clears.
- Paste a full code: every box fills at once.
- With a screen reader, it announces the
aria-labeland the typed value as one field, not six.
API
InputOTPSlot
| Prop | Values | Default | Description |
|---|---|---|---|
| index | number | – | This box's position, from 0. |
All other props come from input-otp.