Code Field
betaOne field for a code typed or pasted: a code sent by email or text, or a workspace's invite code. It drops anything else, and calls onComplete once the code is whole.
Preview
characters
size
states
Install
1. Add the registry to
components.json, once per app. Without it, the shadcn CLI looks up@txbrendanin a public list that txbrendan/ui does not control.npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.
npx shadcn@latest add @txbrendan/theme3. Add the component.
npx shadcn@latest add @txbrendan/code-field
Use it for
- A one-time code sent by email or text: characters="digits", six long by default.
- A join code of letters and digits: characters="text". It shows in capitals.
- Check the code in onComplete. It runs once the code is whole, so there is no Continue button to press.
- Say where the code went and how long it works in hint, like "We sent it to riley@example.com. It works for 15 minutes."
- Put a wrong or expired code in error, like "That code doesn't match".
- Pass onResend to add a quiet "Send a new code" button after the hint or error. It reads "Sent" for 10 seconds after a press.
Avoid it for
- A row of one box per digit. One field takes a paste, autofill, and the phone's suggested code in one go.
- A password or a PIN people choose. Use an input with type="password".
- Long codes people copy from a page, like a licence key. Use an input.
Props
- length
How many characters make the code whole.
number · default 6
- characters
Digits only, or letters and digits in capitals. Anything else is dropped, so a pasted "123 456" reads 123456.
"digits" | "text" · default "digits"
- value
The code. Use it with onValueChange.
string
- defaultValue
The code at first render, when you do not control it.
string
- onValueChange
Called with the cleaned code each time it changes.
(code: string) => void
- onComplete
Called once the code reaches its length. Check it here.
(code: string) => void
- label
Names the field, above it.
ReactNode
- hint
Where the code went and how long it works.
ReactNode
- error
A wrong or expired code. Replaces the hint, in red, and is announced.
ReactNode
- onResend
Adds a "Send a new code" button after the hint or error.
() => void
- resendLabel
The resend button's words.
string · default "Send a new code"
- size
Height, padding, and text size. The same heights as Input.
"sm" | "md" | "lg" · default "md"
- disabled
Blocks typing and the resend button.
boolean · default false
- placeholder
A sample code, like "TEAM26X".
string
- id
The input's id. Defaults to a generated one.
string
- className
Classes for the frame. Other props, like name and aria-*, land on the input.
string
| Prop | Type | Default | What it does |
|---|---|---|---|
| length | number | 6 | How many characters make the code whole. |
| characters | "digits" | "text" | "digits" | Digits only, or letters and digits in capitals. Anything else is dropped, so a pasted "123 456" reads 123456. |
| value | string | - | The code. Use it with onValueChange. |
| defaultValue | string | - | The code at first render, when you do not control it. |
| onValueChange | (code: string) => void | - | Called with the cleaned code each time it changes. |
| onComplete | (code: string) => void | - | Called once the code reaches its length. Check it here. |
| label | ReactNode | - | Names the field, above it. |
| hint | ReactNode | - | Where the code went and how long it works. |
| error | ReactNode | - | A wrong or expired code. Replaces the hint, in red, and is announced. |
| onResend | () => void | - | Adds a "Send a new code" button after the hint or error. |
| resendLabel | string | "Send a new code" | The resend button's words. |
| size | "sm" | "md" | "lg" | "md" | Height, padding, and text size. The same heights as Input. |
| disabled | boolean | false | Blocks typing and the resend button. |
| placeholder | string | - | A sample code, like "TEAM26X". |
| id | string | - | The input's id. Defaults to a generated one. |
| className | string | - | Classes for the frame. Other props, like name and aria-*, land on the input. |
Accessibility
- A native input named by its label, so typing, pasting, and autofill work as usual.
- autocomplete="one-time-code" lets phones offer the code from the message they got.
- Digits open the number keypad on phones. Text codes turn on capitals.
- The hint or error describes the input. An error sets aria-invalid and is announced once when it appears.
- The resend button keeps its width when it reads "Sent", and a polite live region says "Sent a new code".
- On touch screens the text is 16px, so iOS Safari does not zoom in when the field gets focus.
Examples
A code sent by email
<CodeField
label="Code"
hint="We sent it to riley@example.com. It works for 15 minutes."
onComplete={(code) => console.log("check", code)}
onResend={() => console.log("resend")}
/>Letters and digits, seven long
<CodeField
label="Invite code"
characters="text"
length={7}
placeholder="TEAM26X"
hint="Your admin gives you this. It joins you to the right team."
/>A wrong code
<CodeField label="Code" defaultValue="123456" error="That code doesn't match." />