Input OTP
Enter a one-time code digit by digit, with paste and autofill support.
npx prodular-ui add input-otpSix digits
4
8
2
1
Sent to the phone ending in 0417.
import { Field, FieldDescription, FieldLabel } from "@/components/ui/field"import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from "@/components/ui/input-otp"
export default function InputOTPDefault() { return ( <Field className="w-fit"> <FieldLabel htmlFor="otp-code">Verification code</FieldLabel> <InputOTP id="otp-code" maxLength={6} defaultValue="4821"> <InputOTPGroup> <InputOTPSlot index={0} /> <InputOTPSlot index={1} /> <InputOTPSlot index={2} /> </InputOTPGroup> <InputOTPSeparator /> <InputOTPGroup> <InputOTPSlot index={3} /> <InputOTPSlot index={4} /> <InputOTPSlot index={5} /> </InputOTPGroup> </InputOTP> <FieldDescription>Sent to the phone ending in 0417.</FieldDescription> </Field> )}Invalid
Mark each slot with aria-invalid and say how many attempts are left.
1
2
0
9
That PIN does not match. 2 attempts left.
"use client"
import { REGEXP_ONLY_DIGITS } from "input-otp"
import { Field, FieldError, FieldLabel } from "@/components/ui/field"import { InputOTP, InputOTPGroup, InputOTPSlot } from "@/components/ui/input-otp"
export default function InputOTPInvalid() { return ( <Field className="w-fit" invalid> <FieldLabel htmlFor="otp-pin">Recovery PIN</FieldLabel> <InputOTP id="otp-pin" maxLength={4} pattern={REGEXP_ONLY_DIGITS} defaultValue="1209"> <InputOTPGroup> {[0, 1, 2, 3].map((i) => ( <InputOTPSlot key={i} index={i} aria-invalid /> ))} </InputOTPGroup> </InputOTP> <FieldError>That PIN does not match. 2 attempts left.</FieldError> </Field> )}Anatomy
<InputOTP maxLength={6}> <InputOTPGroup> <InputOTPSlot index={0} /> <InputOTPSlot index={1} /> <InputOTPSlot index={2} /> </InputOTPGroup> <InputOTPSeparator /> <InputOTPGroup> <InputOTPSlot index={3} /> <InputOTPSlot index={4} /> <InputOTPSlot index={5} /> </InputOTPGroup></InputOTP>Guidance
Use it when
- Verification and recovery codes of four to eight characters.
Avoid
- Passwords or anything longer than eight characters. Use Input.
Rules for AI agents
Published in llms-full.txt, the registry and the MCP server, so coding agents follow them when they build with this component.
- Set maxLength to the code length and render one InputOTPSlot per index.
- Use pattern={REGEXP_ONLY_DIGITS} from input-otp for numeric codes.
- Give InputOTP an id and pass it to FieldLabel htmlFor.
- Say where the code was sent in FieldDescription.
API
InputOTP
| Prop | Type | Default | Description |
|---|---|---|---|
| maxLength | number | Number of characters. | |
| pattern | string | Allowed characters as a regular expression string. |
InputOTPSlot
| Prop | Type | Default | Description |
|---|---|---|---|
| index | number | Which character this slot shows. |
Installation
The Prodular UI CLI adds the source to components/ui with everything it depends on. In a project that already uses shadcn/ui, the shadcn CLI installs it from the Prodular registry too. See Installation for the first setup.
npx prodular-ui add input-otp# or, with the registry in components.jsonnpx shadcn@latest add @prodular/input-otp