OneTimeCodeField
One input for a one-time code, drawn as a slot per digit, that takes a pasted or autofilled code whole.
import { OneTimeCodeField } from "@butteryui/react";Demo
The code works for 10 minutes.
When to use it
Use it for
- The code step of a passwordless sign-in or sign-up, as AuthFlow draws it
- Confirming an email address or a phone number with a code sent to it
- A short numeric code someone reads off another screen, such as a locker or pairing code
Not for
- A password or a code with letters: use PasswordField or TextField
- A whole sign-in screen: use AuthFlow, which brings the identifier step and the resend timer
Examples
Confirm a phone
Confirming a new phone number in account settings with the code texted to it; 112233 confirms it.
Phone number
We texted a code to (503) 555-0142 to check it's yours.
Four digits
A shorter code for a pickup locker, and the field's look while a code is checked and once it's accepted.
Opening locker 12…
Locker 12 is open
New device
Both looks: an outlined code field on a page, and a soft one in a settings panel that confirms a new device.
The code works for 10 minutes.
Type the six digits it shows.
Pasted code
A code pasted with its dash keeps only its digits, and the field says when it's whole.
Paste the code from your message, dash and all.
0 of 6 digits
Verify code
A code checked as soon as its last digit is in: 246810 signs in, any other code is turned down.
The code works for 10 minutes.
Variants and states
States
Waiting for a code with a note, checking one, accepted, and turned down with what to do next.
The code works for 10 minutes.
Verifying…
Signed in
That code isn't right. Check it and try again.
Lengths
A slot for each digit, from a 4-digit locker code to an 8-digit one.
Props
OneTimeCodeField
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | "One-time code" | What the field asks for, read with it. Defaults to "One-time code". |
hideLabel | boolean | false | Keeps the label for screen readers without showing it, for a step whose title already asks. Defaults to false. |
variant | "outline" | "soft" | "outline" | "outline" (the default), or "soft", a filled box whose edge shows on hover and focus, as every text input takes. |
length | number | 6 | Digits in the code, one slot each. Defaults to 6. |
value | string | The digits typed so far. Pair with onValueChange to control it. | |
defaultValue | string | The digits it starts with when uncontrolled. | |
onValueChange | ((value: string) => void) | Called with the digits on every change; anything else typed or pasted, such as a dash, is left out. | |
onComplete | ((code: string) => void) | Called once with the code when every slot is filled; filling it with the same code again doesn't call it twice. | |
status | "idle" | "verifying" | "success" | "error" | "idle" | Where the code stands. "error" draws the danger color and takes focus back. Defaults to "idle". |
message | ReactNode | A note under the field, such as how long the code lasts, or what went wrong while status is "error". | |
labels | Partial<OneTimeCodeLabels> | The words for checking and success. | |
webOtp | boolean | false | Fills in a code from a text message where the browser offers it (the Web OTP API). Defaults to false. |
It also takes Omit<ComponentPropsWithRef<"input">, "value" | "defaultValue" | "children" | "size" | "maxLength" | "type" | "inputMode" | "autoComplete">.
OneTimeCodeLabels
The words a `OneTimeCodeField` shows while it checks a code and once it's accepted.
| Field | Type | Default | Description |
|---|---|---|---|
verifyingrequired | string | "Verifying…" | Under the field while the code is checked. Defaults to "Verifying…". |
successrequired | string | "Signed in" | Under the field once the code is accepted. Defaults to "Signed in". |
Accessibility
It's one real input with a label ("One-time code" by default, kept for screen readers with hideLabel), numeric and marked autocomplete="one-time-code", so the system's code from a message, a password manager and a paste all fill it at once. The slots are drawn for the eye and hidden from screen readers, which read the input's value. The note or status under the field describes the input, and checking, success and errors are read out as they happen. An error takes focus back to the field.
| Keys | What they do |
|---|---|
| Digits | Fill the next slot; anything else typed is left out |
| Backspace | Clears the digit before the caret |
| Arrow left and right | Move between slots |
| Enter | Submits the form it's in |
Motion
It appears with a `Presence` preset and leaves faster than it came, in about 60% of the time.
With reduced motion: The check appears at once and the caret holds still; the border and fill still change color.
Layout
It fills its container's width, its slots sharing it evenly. The box is --bt-h-cta (48px) tall, and the whole box takes presses and pastes. The line under it is kept in every state, so a status coming or going never moves what's below.