OTP field
A one-time code entry, wrapping the Base UI OTP Field: length renders the slots, typing and pasting distribute across them, and the value stays one string. Wrap it in a Field for a label and validation.
Playground
Every control maps to a prop. Try pasting a full code; the Code tab always shows the markup for exactly what you've configured.
Variants
Slots are squares at the two library sizes, 36px by default and 28px compact, and mask hides the characters for codes that double as passwords.
States
Slots carry data-filled as they fill and the root carries data-complete once the last one does. Invalid comes from the surrounding Field (the field has no invalid prop of its own), and disabled dims every slot.
Styling states
The root carries data-complete once every slot is filled; each slot carries data-filled, data-invalid, and data-disabled:
.ub-otp-field[data-complete] .ub-otp-field-input {
border-color: var(--ub-success);
}Props
Everything the Base UI OTP Field root accepts passes through. The essentials:
| Prop | Type | Default | Description |
|---|---|---|---|
length | number | โ | How many characters the code has; renders that many slots. |
value | string | โ | The whole code as one string (also defaultValue, onValueChange). |
onValueChange | (value: string) => void | โ | Fires per keystroke; check value.length against length for completion. |
autoSubmit | boolean | false | Submits the surrounding form once the code is complete. |
mask | boolean | false | Hides the entered characters, for codes that act like passwords. |
size | "default" | "compact" | "default" | Default slots are 36px tall with 16px text; compact are 28px with 14px text. |
Agent instructions
Working with a coding agent? Paste this into its context, or point it at llms.txt for the whole library.
OTPField, from @usebones/react.
- One component: length renders the slots; value/defaultValue/onValueChange treat the code as one string. Typing, pasting, and arrow keys are handled.
- Wrap in FieldRoot + FieldLabel in real forms (label and validation wire automatically), or pass aria-label. There is no invalid prop; invalid state comes from FieldRoot.
- autoSubmit submits the surrounding form when complete; mask hides characters; autoComplete defaults to one-time-code so SMS autofill works.
- size "default" (36px slots) | "compact" (28px).
- Restyle in CSS via .ub-otp-field, .ub-otp-field-input, [data-complete] on the root, [data-filled]/[data-invalid]/[data-disabled] on slots. Tokens only.