OTP Input
OTP inputs allow users to enter verification codes with individual character slots. They support configurable lengths, visual separators, masking, and completion callbacks.
OTP Input Playground
OTP Input Playground
Preview
Code
-
Controls
Length:
4
6
Size:
Default
Large
Separator:
Mask:
Disabled:
Installation
You can add the otp input component to your project manually:
1
Install the following dependencies:
npm
pnpm
yarn
bun
npm install class-variance-authority clsx tailwind-merge2
Copy and paste the following code into your project.
OTPInput.tsx
OTPInputBlock.tsx
cn.ts
Loading source code...
3
Update the import paths to match your project setup.
Update the import aliases (e.g. @/components, @/utils) in the copied files to match your project's path configuration.
Basic Usage
import { OTPInput } from '@versaui/ui/components/OTPInput';
<OTPInput
length={6}
onComplete={(code) => verify(code)}
/>Length Variants
Supports 4-digit PINs or 6-digit verification codes:
// 4-digit PIN
<OTPInput length={4} />
// 6-digit code (default)
<OTPInput length={6} />With Separator
Add a visual dash between groups of digits:
// 6-digit with separator after 3rd slot: XXX-XXX
<OTPInput length={6} separator={3} />
// 4-digit with separator after 2nd slot: XX-XX
<OTPInput length={4} separator={2} />Size Variants
<OTPInput size="default" />
<OTPInput size="large" />Masked Input
Hide entered characters for sensitive codes:
<OTPInput length={6} mask />Error State
Show validation errors with an optional message:
// Boolean error
<OTPInput length={6} error />
// With error message
<OTPInput length={6} error="Invalid verification code" />Controlled Usage
const [otp, setOtp] = useState('');
<OTPInput
length={6}
value={otp}
onChange={(value) => setOtp(value)}
onComplete={(code) => submitVerification(code)}
/>Accessibility
- Each input slot is individually focusable
- Auto-advances focus on character input
- Backspace navigates to previous slot
- Arrow keys, Home, End for slot navigation
- Full paste support for code entry
- Error state announced to screen readers via
aria-label
OTPInput Props
| Prop | Type | Default | Description |
|---|---|---|---|
length | 4 | 6 | 6 | Number of OTP digit slots. |
separator | number | — | Position to show separator (e.g. 3 for XXX-XXX). |
size | 'default' | 'large' | 'default' | Input slot size. |
value | string | — | Controlled input value. |
defaultValue | string | '' | Initial value for uncontrolled usage. |
inputMode | 'numeric' | 'text' | 'numeric' | Input keyboard type. |
mask | boolean | false | Mask entered characters. |
disabled | boolean | false | Prevents interaction. |
readOnly | boolean | false | Read-only state. |
error | boolean | string | false | Error state or message. |
autoFocus | boolean | false | Focus first slot on mount. |
onChange | (value: string) => void | — | Called on each character input. |
onComplete | (value: string) => void | — | Called when all slots are filled. |
aria-label | string | 'Verification code' | Accessible label for screen readers. |
className | string | '' | Additional CSS classes. |