Input OTP

Forms
Security

One-Time Password input for verification codes, PIN codes, and security authentication. Features auto-focus, paste support, and keyboard navigation.

Preview

6-digit verification code input

With Separator

Visual separator between digit groups (e.g., 123-456)



PIN Code

4-digit PIN input with password masking

Text Type

Accept alphanumeric characters

Error State

Show error when validation fails

Try entering "123456" for success, or any other code to see error state.

Props

InputOTP component API reference

PropTypeDefaultDescription
lengthnumber6Number of input fields
valuestring''Controlled value
onChange(value: string) => voidCallback when value changes
onComplete(value: string) => voidCallback when all fields filled
type'number' | 'text' | 'password''number'Input type and keyboard
separatorbooleanfalseShow separator between groups
separatorAfternumber3Position of separator
labelstringLabel text above inputs
errorboolean | stringfalseError state and message
disabledbooleanfalseDisable all inputs
classNamestringAdditional CSS classes

Usage

Import and implementation example

import { InputOTP } from '@/components/ui/input-otp'

export default function Example() {
  const [code, setCode] = useState('')
  const [error, setError] = useState<string | false>(false)

  const handleComplete = async (value: string) => {
    try {
      await verifyCode(value)
      // Success - redirect or show success state
    } catch (err) {
      setError('Invalid code. Please try again.')
    }
  }

  return (
    <>
      {/* Basic 6-digit code */}
      <InputOTP
        label="Verification Code"
        length={6}
        value={code}
        onChange={setCode}
        onComplete={handleComplete}
        error={error}
      />

      {/* With separator */}
      <InputOTP
        label="Enter Code"
        length={6}
        value={code}
        onChange={setCode}
        separator
        separatorAfter={3}
      />

      {/* 4-digit PIN */}
      <InputOTP
        label="PIN Code"
        length={4}
        value={code}
        onChange={setCode}
        type="password"
      />

      {/* Alphanumeric */}
      <InputOTP
        label="License Key"
        length={6}
        value={code}
        onChange={setCode}
        type="text"
      />
    </>
  )
}

Features

Built-in functionality

  • Auto-focus next: Automatically moves to next field on entry
  • Backspace navigation: Move to previous field on backspace
  • Arrow key navigation: Navigate between fields with arrow keys
  • Paste support: Paste entire code to fill all fields
  • Optional separator: Visual separator between digit groups
  • Three input types: Number, text, or password (masked)
  • Completion callback: Triggers when all fields are filled
  • Error state: Custom error messages with visual feedback
  • Configurable length: 4, 6, 8 or any number of digits
  • Dark mode: Full dark mode support

Accessibility

Accessibility considerations

ARIA Attributes

Each input is properly labeledError messages linked via aria-describedbyInput mode set for appropriate keyboard

Keyboard Navigation

KeyAction
TabFocus first/next input field
Arrow Left/RightNavigate between fields
BackspaceClear current field, move to previous
PasteFill all fields from clipboard

Notes

  • Focus automatically advances on input
  • Error state communicated visually and semantically
  • Password type masks input for security
  • Numeric keyboard shown on mobile for number type

Related Components