Components
Input OTP
A segmented field for entering short codes one slot at a time. It auto-advances as you type and handles pasting a full code at once.
Preview
Rendered with live Cognition tokens. Click a slot and type, no dark: classes.
Variants
<InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS}>pattern={REGEXP_ONLY_DIGITS_AND_CHARS}Numeric is the common case for verification codes. Alphanumeric accepts letters and digits for codes that mix both.
States
Default. Empty, at rest.
Active. The focused slot rings (shown statically here).
Filled. A complete code.
Error. The code was rejected.
<InputOTP disabled>Active highlights the slot taking input. Filled, error, and disabled read across the whole field.
API
Slots are composed with InputOTPGroup, InputOTPSlot, and InputOTPSeparator.
Don't and Do
Don't use an OTP field for general short text. It carries a specific interaction contract, auto-advance and full-code paste, that will confuse people when applied to a name, a code word, or anything that is not entered slot by slot. Use a plain Input for those.
<InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS}>
<InputOTPGroup>
<InputOTPSlot index={0} />
<InputOTPSlot index={1} />
<InputOTPSlot index={2} />
</InputOTPGroup>
<InputOTPSeparator />
<InputOTPGroup>
<InputOTPSlot index={3} />
<InputOTPSlot index={4} />
<InputOTPSlot index={5} />
</InputOTPGroup>
</InputOTP>Use it for verification codes, PIN entry, and any segmented numeric input where slot-by-slot entry is expected.
import {
InputOTP,
InputOTPGroup,
InputOTPSlot,
} from "@/components/ui/input-otp";
import { REGEXP_ONLY_DIGITS } from "input-otp";
export function VerifyCode() {
return (
<InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS}>
<InputOTPGroup>
{[0, 1, 2, 3, 4, 5].map((i) => (
<InputOTPSlot key={i} index={i} />
))}
</InputOTPGroup>
</InputOTP>
);
}