Basel Standard / Docs
Input OTP
Multi-slot verification input for short codes that need explicit position, focus, and scan order.
Use the grouped slots when a short verification code needs clear position and keyboard focus.
InputOTP turns a short verification code into a grouped sequence of slots without losing the single-input interaction model. It works well when the user should understand code length, current position, and completion state at a glance.
Installation
Purchase access, then open /account/install to issue a registry token.Usage
import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from "@/components/ui/input-otp"
<InputOTP maxLength={6}>
<InputOTPGroup>
<InputOTPSlot index={0} />
<InputOTPSlot index={1} />
<InputOTPSlot index={2} />
</InputOTPGroup>
<InputOTPSeparator />
<InputOTPGroup>
<InputOTPSlot index={3} />
<InputOTPSlot index={4} />
<InputOTPSlot index={5} />
</InputOTPGroup>
</InputOTP>
Why This Primitive Exists
A verification code should be easy to scan and hard to misread. The slot layout makes the expected length explicit while the underlying input model still handles typing, paste, and keyboard movement as one control.
- Use it for short one-time codes, confirmation steps, or secure handoff gates.
- Use separators when the code benefits from chunking, such as
123-456. - Avoid it for ordinary numeric entry, passwords, or identifiers that should behave like a normal text field.
Examples
Basic Six-Digit Entry
The default grouped layout is enough for most verification steps.
Use the grouped slots when a short verification code needs clear position and keyboard focus.
<InputOTP maxLength={6}>
<InputOTPGroup>
<InputOTPSlot index={0} />
<InputOTPSlot index={1} />
<InputOTPSlot index={2} />
<InputOTPSlot index={3} />
<InputOTPSlot index={4} />
<InputOTPSlot index={5} />
</InputOTPGroup>
</InputOTP>
Chunked With A Separator
Split the code visually when the user will scan or read it in grouped segments.
Separators help a longer code scan as two chunks without breaking the single input model.
<InputOTP maxLength={6}>
<InputOTPGroup>{/* first 3 slots */}</InputOTPGroup>
<InputOTPSeparator />
<InputOTPGroup>{/* last 3 slots */}</InputOTPGroup>
</InputOTP>
In Context
Keep the code input next to the explanation and recovery actions so the interruption still feels local to the workflow.
Verification step
We sent a six-digit approval code to the archive owner before release access can be restored.
Current value: Waiting for code
<CardContent>
<p>We sent a six-digit approval code to the archive owner.</p>
<InputOTP maxLength={6}>{/* grouped slots */}</InputOTP>
</CardContent>
Guidance
Use OTP Only For Short Codes
- Keep lengths short and explicit.
- Use a normal input when the value is longer, editable, or not time-sensitive.
- Pair the control with nearby copy that says where the code was sent and why it is required.
Preserve The Single-Input Model
- Treat the slots as one field, not six independent inputs.
- Let paste fill the full sequence when the underlying library supports it.
- Avoid inserting extra logic per slot unless the interaction genuinely requires it.
Keep Recovery Actions Nearby
- Provide resend or alternate verification actions close to the input.
- Explain expiry, delivery delay, or fallback paths in short supporting copy.
- If the code step belongs to a larger confirmation surface, keep it inside that card or modal rather than on a disconnected page.
API Reference
Exports
| Export | Renders | Notes |
|---|---|---|
InputOTP | OTPInput | Root input wrapper that manages the code value and slot context. |
InputOTPGroup | div | Groups a run of adjacent slots. |
InputOTPSlot | div | Individual rendered slot; requires an index. |
InputOTPSeparator | div | Visual divider between slot groups. |
InputOTP
InputOTP forwards the underlying OTPInput props, including controlled and uncontrolled value handling.
| Prop | Type | Notes |
|---|---|---|
maxLength | number | Required for most compositions so the slot count matches the expected code length. |
value | string | Controlled current value. |
onChange | (value: string) => void | Fired whenever the code changes. |
containerClassName | string | Extends the outer flex wrapper around the slot groups. |
className | string | Extends the underlying hidden input element. |
InputOTPSlot
| Prop | Type | Notes |
|---|---|---|
index | number | Required slot index into the current OTP context. |
className | string | Extends the slot styling for custom width or emphasis. |
InputOTPGroup and InputOTPSeparator also forward their native div props directly.