Input OTP
A one-time code made of grouped digit slots.
Overview
One native input holds the digits, so paste, arrows, and backspace stay with the browser. The slots are visual. Set name when the value should submit with a form. Use onComplete to react when every digit is filled.
Preview
Customize
Length
4
Invalid
Installation
Add the component with the CLI. It copies the files in and installs anything they depend on.
npx vinyaas add input-otpUsage
import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from "@/components/ui/input-otp";
export function Code() {
return (
<InputOTP length={6} aria-label="Verification code">
<InputOTPGroup>
<InputOTPSlot index={0} />
<InputOTPSlot index={1} />
<InputOTPSlot index={2} />
</InputOTPGroup>
<InputOTPSeparator />
<InputOTPGroup>
<InputOTPSlot index={3} />
<InputOTPSlot index={4} />
<InputOTPSlot index={5} />
</InputOTPGroup>
</InputOTP>
);
}Examples
PIN
A shorter code uses the same slots with length 4.
Invalid
invalid marks the field and the slots.
Disabled
A disabled code cannot be edited.
In practice
Confirm a sign-in email with a six-digit code, Verify, Resend, and success or error copy.
API
Other attributes for the underlying element are passed through.
| Name | Type | Default | Description |
|---|---|---|---|
length | number | — | How many digits the field accepts. Defaults to 6. |
value | string | — | Controlled digits. Non-digits are ignored. |
onChange | (value: string) => void | — | Called with the cleaned digit string. |
onComplete | (value: string) => void | — | Called once when the value reaches length. Fires again after a digit is removed and the code is completed again. Does not fire while disabled. |
invalid | boolean | — | Sets aria-invalid and the destructive slot border. |
Accessibility
- The input is named with aria-label or a label and id.
- Slots are hidden from assistive technology.
- invalid sets aria-invalid.
- Paste fills the digits from the clipboard.