Input OTP
A one-time code on short baselines, three and three. Digits drop in as you type; whole, the lines ink in turn. Or the code closes up into one figure, or is read back in words under its digits.
Report an issue with Input OTPExample
For this page, the code is 246810.
For this page, the code is 246810.
For this page, the code is 246810.
Waiting
Whole
Wrong
close-up, waiting
close-up, whole
close-up, wrong
lyric, waiting
lyric, whole
Install
Run it in a project that has the shadcn CLI set up. It brings the 0nlyType base and field along.
npx shadcn@latest add https:// thedirectors.agency/ ui/ r/input-otp.jsonUsage
"use client"import * as React from "react"import { Field } from "@/components/ui/field"import { InputOTP, type InputOTPProps } from "@/components/ui/input-otp"// For this page, the code we sent is 246810.function Check({ label, variant }: { label: string; variant?: InputOTPProps["variant"] }) {const [error, setError] = React.useState<string>()return (<Field label={label} hint="For this page, the code is 246810." error={error} className="max-w-md"><InputOTPvariant={variant}onValueChange={() => setError(undefined)}onComplete={(code) => code !== "246810" && setError("That code doesn't match. Check the message and type it again.")}/></Field>)}export default function Example() {return (<div className="grid gap-12"><Check label="The code we sent to your phone" /><Check label="The code from your email" variant="close-up" /><Check label="The code we read to you" variant="lyric" /></div>)}Contract
- Underneath: native input, plus a hook.
- Anatomy:
<div class="ot-code">holding one<input inputmode="numeric" autocomplete="one-time-code" maxlength="6">and six.ot-code-slotspans split three and three by.ot-code-sep, a leaning hairline. Script copies the digits into the slots and setsdata-hereon the next slot anddata-state="done | wrong"on the box. - Each digit drops onto its baseline in italic (
ot-drop-in); the waiting line is the accent. Whole, the lines ink in turn. Wrong, they turn crimson together and anot-field-errorsays why. - One real input underneath, so paste, autofill and the keyboard all work natively.
- Variant
close-up(the proofreader's close-up mark; the tight tracking of "the uncreative"): a dot waits for each digit, the next one in the accent. Whole, the spaces close and the halves meet in one tight figure; the mark's two arcs land over and under the join. Wrong, the spaces open again in crimson. - Variant
lyric(the score's lyric line; a cheque's sum in words): each digit is read back in words under its line (.ot-code-word, ours, upright), with a comma at the halfway breath and a full stop at the end, so the code can be checked aloud against the message. Whole, the words ink.
Props
| Prop | Type | Default | What it does |
|---|---|---|---|
variant | "line" | "close-up" | "lyric" | "line" | How the code waits and ends. line: short baselines, three and three; whole, they ink in turn. close-up: a dot waits for each digit, the next in the accent; whole, the spaces close into one tight figure and the proofreader's close-up mark lands over and under the join. lyric: each digit is read back in words under its line, as lyrics sit under their notes, with a comma at the halfway breath and a full stop at the end, so the code can be checked aloud. |
length | number | 6 | How many digits. |
group | number | A separator stands after every this many slots. Three and three for six. | |
value / defaultValue / onValueChange | string | The digits typed so far. Anything that isn't a digit is dropped. | |
onComplete | (value: string) => void | Called once, when the last slot fills. | |
aria-invalid | boolean | Whole and wrong, the lines turn crimson together. Inside a Field with an error this is set for you. |
Craft
Where its move comes from
| Component | Reference | Move |
|---|---|---|
| One-time code | "Less is more." rules | Short baselines, three and three |
| Close-up code | The proofreader's close-up mark; "the uncreative" | Dots wait; whole, the code closes into one figure |
| Lyric code | The score's lyric line; a cheque's sum in words | Each digit read back in words under it |
How it moves
| Component | Articulation | What moves |
|---|---|---|
| One-time code | Drop | Each digit drops onto its line; whole, the lines ink in turn |
| Close-up code | Close up | Whole, the spaces close; the two arcs land over and under the join |
| Lyric code | Read back | Each word opens from its middle under its digit |