OTP input
One-time code / PIN boxes. 2 lengths × 4 states.
import * as React from "react";
import { OtpInput } from "@/components/ui/otp-input";
export default function Example() {
const [done, setDone] = React.useState("");
return (
<div style={{ display: "grid", gap: 12, justifyItems: "center" }}>
<OtpInput length="6" aria-label="Verification code" onComplete={setDone} />
<span className="text-body-small text-fg-secondary">{done ? `Code entered: ${done}` : "We sent a 6 digit code to 01712 345678."}</span>
</div>
);
}
Installation
$ npx uix-ui@latest add otp-inputThis copies the file into components/ui/otp-input.tsx in your project. npx shadcn@latest add @uix/otp-input works too.
Usage
import { OtpInput } from "@/components/ui/otp-input";
<div style={{ display: "grid", gap: 12, justifyItems: "center" }}>
<OtpInput length="6" aria-label="Verification code" onComplete={setDone} />
<span className="text-body-small text-fg-secondary">{done ? `Code entered: ${done}` : "We sent a 6 digit code to 01712 345678."}</span>
</div>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
length | 4 | 6 | "6" | |
value | string | – | The code typed so far (controlled). |
defaultValue | string | "" | |
onValueChange | (value: string) => void | – | Called on every change with the digits so far. |
onComplete | (value: string) => void | – | Called once every box is filled. |
error | string | – | Error message; also marks the boxes invalid. |
helper | React.ReactNode | – | Text under the boxes. |
name | string | – | Name of a hidden input that carries the code in a form. |
disabled | boolean | false |
Everything else is passed to the root element, so className, aria-* and event handlers work as usual.
Dependencies
Installed for you by the CLI.
class-variance-authorityclsxtailwind-merge
lib/utils.ts