Input OTP
A segmented input for short fixed-length codes (one-time passwords, 2FA, PINs).
@garn/ui/input-otpDefault
A 6-digit code split 3 + 3.
Installation
garn is copy-in — the garn CLI writes this component's source into your project, so you own and can edit it. It resolves any base files and installs the npm dependencies below for you.
npx garn-ui add input-otp- Registry
input-otp- Source
- input-otp.tsx
- Deps
input-otplucide-react- Registry deps
utils
Import
import { InputOTP } from "@garn/ui/input-otp";Props
Generated from the component's TypeScript types.
No component-specific props — this is a thin wrapper over its native element.
Styling
Target these data-slots and remap these tokens to restyle without forking the component.
[data-slot="input-otp"]| Property | Token | Tier |
|---|---|---|
slotSize | --garn-control-h-md | semantic · air |
Overview
InputOTP collects a short, fixed-length code — a one-time passcode, 2FA token, email/phone verification, or PIN — as a row of single-character slots. InputOTP owns the value (maxLength sets the slot count), InputOTPGroup clusters slots, InputOTPSlot is one cell by index, and InputOTPSeparator splits a long code (3 + 3). For general or variable-length text use Input; for a secret password use a password Input.
Guidelines
Use it only for short, fixed-length codes. It's built for 4–8 known characters; anything variable-length or freeform belongs in a regular Input. Match maxLength to the real code and group long codes (e.g. 3 + 3) for readability.
Make entry effortless. Support paste-to-fill-all and auto-advance between slots, set the right inputMode/autoComplete (one-time-code) so mobile keyboards and SMS autofill work, and auto-submit when the last slot fills if that fits the flow.
Keep it accessible and recoverable. The field needs an accessible name, and the slots should read as one input to assistive tech, not N anonymous boxes. On a wrong code, show a clear error and let the user retry or request a new code rather than silently clearing.
Best practices
- Set
maxLengthto the exact code length; group long codes (e.g. 3 + 3) with a separator. - Use inputMode/pattern so mobile shows the right keyboard for numeric codes.
- Don't use it for free text.
- Don't omit a label — the slots aren't self-describing.
Content guidelines
- Label the field with what the code is for (“Verification code”).
- State the length and source (“6-digit code from your email”).
Accessibility
- Role
textbox- Focus
- The active slot shows the shared field-surface focus treatment (foreground/40 edge + neutral ring) and a blinking caret; focus stays on the single input.
Enforceable contracts
Give the OTP input an accessible label (aria-label or a <label>).
when the InputOTP has no aria-label / aria-labelledby / associated label
Keyboard
| 0–9 / A–Z | Fill the active slot and advance. |
| Backspace | Clear and step back. |
| Paste | Distributes a pasted code across the slots. |
- • A single underlying input drives the slots; label it (aria-label / a Label).
- Status
- Stable
- Version
v0.3.0- Introduced
v0.1.0
garn doesn't yet record a per-release version history. This reflects the component's current lifecycle state; full changelog entries will appear once the metadata pipeline emits a lifecycle.history field.