components / form
OTP Input
One box per digit with auto-advance, backspace, and paste.
539 B gzip client componentbase ui · otp-field
type or paste 6 digits
otp-input-default.tsx
"use client";
import { useState } from "react";
import { OtpInput } from "@/components/ui/otp-input";
export default function OtpInputDefault() {
const [code, setCode] = useState("");
return (
<div className="flex flex-col gap-3">
<OtpInput onValueChange={setCode} value={code} />
<p className="font-mono text-muted-foreground text-sm">{code.length === 6 ? `code: ${code}` : "type or paste 6 digits"}</p>
</div>
);
}Installation
$ npx shadcn@latest add https://cd-ui.vercel.app/r/otp-input.jsonfirst time? set up components.json and the theme first: see installation.
Usage
import { OtpInput } from "@/components/ui/otp-input"
<OtpInput length={6} onValueComplete={(code) => verify(code)} />API
OtpInput
Base UI · OTPField.RootOne box per digit, built on Base UI's OTP Field. Numeric by default, with autofill from SMS (autocomplete="one-time-code").
| prop | type | default |
|---|---|---|
lengthNumber of boxes. | number | 6 |
value · defaultValueCode as a string. Controlled or initial. | string | - |
onValueChangeCalled on every change. | (value: string) => void | - |
onValueCompleteCalled when every box is filled. | (value: string) => void | - |
invalidPaints the boxes with the error color. | boolean | - |
classNameExtra classes, merged with | string | - |
Keyboard
| key | action |
|---|---|
| 0-9 | Fills the box and moves to the next one. |
| Backspace | Clears the box and goes back to the previous one. |
| ←→ | Moves between boxes. |
| CtrlV | Pasting a full code fills every box. |
Accessibility
- The boxes sit in a
role="group"labelled "Verification code" (change it witharia-label); each box after the first is named "Digit N of 6".