A one-time code in separate slots, with paste, SMS autofill and a pattern.
Example
import { InputOTP, REGEXP_ONLY_DIGITS } from "@elements/ui/input-otp";
<InputOTP value={form.code} maxLength={6} groups={[3, 3]} pattern={REGEXP_ONLY_DIGITS} />
<InputOTP value={form.pin} maxLength={4} onComplete={(code) => verify(code)} />
Parts
| Part |
What it is |
.input-otp |
The root. |
.input-otp-input |
The real input, transparent over the slots. |
.input-otp-group |
A run of joined slots. |
.input-otp-slot |
One character. |
.input-otp-separator |
Between groups. |
.input-otp-caret |
The blinking caret in an empty active slot. |
Attributes
| Attribute |
Type |
Default |
Description |
value |
string (two-way) |
"" |
The code. |
maxLength |
number |
6 |
Number of slots. |
groups |
number[] |
[] |
Slots per group, e.g. [3, 3]. A separator goes between groups. |
pattern |
string | RegExp |
"" |
Every change must match. REGEXP_ONLY_DIGITS, REGEXP_ONLY_CHARS and REGEXP_ONLY_DIGITS_AND_CHARS are exported. |
pasteTransformer |
((pasted: string) => string) | null |
null |
Cleans pasted text first, e.g. removes dashes. |
inputmode |
"numeric" | "text" | "decimal" | "tel" | "email" | "url" | "search" | "none" |
"numeric" |
Which keyboard a phone shows. |
autocomplete |
string |
"one-time-code" |
Lets the browser fill a code from an SMS. |
placeholder |
string |
"" |
One placeholder character per empty slot. |
pushPasswordManagerStrategy |
"increase-width" | "none" |
"increase-width" |
Keeps a password manager's badge off the last slot. |
textAlign |
"left" | "center" | "right" |
"left" |
Where the hidden input's text sits, which is where a click-hold or long press lands (input-otp textAlign). |
inputClass |
string |
"" |
Classes added to the real input (input-otp className). |
size |
"sm" | "md" | "lg" |
"md" |
Slot size from the control heights. |
name |
string |
"" |
Submits the code with its form. |
disabled |
boolean |
false |
Not interactive. |
readonly |
boolean |
false |
Focusable and submitted, but typing and paste do nothing. |
required |
boolean |
false |
The form will not submit until every slot is filled. |
invalid |
boolean |
false |
Danger borders on the slots. |
class |
string |
"" |
Extra classes on the root. |
attrs |
Record<string, string | number | boolean | undefined> |
{} |
Attributes for the input: id, aria-label, autofocus, data-*. |
onValueChange |
(value: string) => void |
() => {} |
Called with the new code on every change the user makes (input-otp onChange). |
onComplete |
(value: string) => void |
() => {} |
Called once when the last slot fills. |
Slots
| Slot |
Content |
separator |
Shown between groups. Default: a dash. |
Keyboard
| Keys |
Action |
Type |
Fills the active slot and moves on. |
Backspace |
Deletes the active slot's character. |
ArrowLeft / ArrowRight |
Moves between slots. |
Home / End |
Moves to the first slot, or the slot after the code. |
Ctrl/Cmd + V |
Pastes a whole code. |
Data attributes
| Attribute |
Values |
On |
data-active |
present on the slot being edited |
slot |
data-filled |
present when the slot has a character |
slot |
data-placeholder |
present while a placeholder shows |
slot |
data-index |
the slot's index |
slot |
data-complete |
present when every slot is filled |
root |
data-disabled |
present when disabled |
root |
data-readonly |
present when read-only |
root |
data-invalid |
present when invalid |
root |
Accessibility
- It is one text input, so a screen reader reads and edits the code as one field; the slots are drawing only (aria-hidden).
- autocomplete="one-time-code" lets iOS and Android offer the code from an SMS, and a pasted code fills every slot.
- Name it with a Field or aria-label through attrs.
See also
- Slider (opens in a new tab): Pick a value or a range by dragging thumbs along a track, with full keyboard support.
- NumberInput (opens in a new tab): A number field with stepper buttons, keyboard steps, formatting, wheel and scrub.
- PasswordInput (opens in a new tab): A password field with a button that shows and hides what was typed.
- TagsInput (opens in a new tab): Type a list of tags into one field: add, edit, delete and paste them from the keyboard.
- ColorPicker (opens in a new tab): Pick a color with an area, channel sliders, inputs, swatches and the eye dropper.
- FileUpload (opens in a new tab): Drop, paste or browse for files; see them listed with previews, sizes, errors and progress.