Skip to content

InputOTP

<InputOTP> is the one-time-code input — typically 6 digits for SMS / TOTP. Each character has its own slot; paste fills all slots; auto-advances on type. Adapted from shadcn’s canonical implementation; uses input-otp under the hood.

import from "@na/ui/components/InputOTP" ▶ Open in Storybook packages/ui/src/components/InputOTP.tsx

When to use

  • SMS / TOTP verification codes during sign-in or 2FA.
  • Email-link verification codes.
  • Any short fixed-length numeric or alphanumeric code.

Don’t use InputOTP for: passwords (PasswordInput), free-form codes the user types from memory (use a regular Input), or long codes (≥ 8 chars feels gimmicky).

Six-digit (default)

Paste a 6-digit code anywhere — it fills all slots.

<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>

Four-digit

<InputOTP maxLength={4}>
<InputOTPGroup>
<InputOTPSlot index={0} />
<InputOTPSlot index={1} />
<InputOTPSlot index={2} />
<InputOTPSlot index={3} />
</InputOTPGroup>
</InputOTP>

Anatomy

InputOTP (root, manages the buffer) → one or more InputOTPGroups → each group contains InputOTPSlots indexed 0..maxLength-1. Use InputOTPSeparator between groups.

API

InputOTP

Prop Type Default Description
maxLength * number Total slot count.
value string Controlled value. Pair with onChange.
onChange (value: string) => void Fires on every keystroke / paste.
onComplete (value: string) => void Fires exactly once when value reaches maxLength.
disabled boolean false Disable all slots.
pattern string RegExp source — restrict accepted characters (e.g. /^[0-9]+$/).

InputOTPSlot

Prop Type Default Description
index * number 0-based slot index. Must be unique and within [0, maxLength).
className string Forwarded.

InputOTPGroup and InputOTPSeparator accept native div attributes. The separator is decorative.

Design guidelines

✓ Do

  • Use 6 digits for SMS / TOTP. Industry standard; users recognize it instantly.
  • Set onComplete to auto-submit. Asking the user to also click Submit after typing 6 digits is friction.
  • Pair with FormError below for invalid-code messages.

✗ Don't

  • Use InputOTP for passwords. Slots advertise length and break password managers.
  • Disable paste. Users paste from SMS / authenticator apps; they'll abandon if you block it.
  • Show codes longer than 8 slots. Users mis-remember; reach for QR or magic link.

Accessibility

  • The underlying <input> is the focusable element; slots are visually-rich representations.
  • Keyboard: type to fill, Backspace to clear and back-step, Arrow keys to navigate.
  • Paste anywhere in the OTP fills all slots (browser standard).

▶ Open InputOTP stories in Storybook