OTP Field

An OTP field lets users enter a one-time passcode across multiple single-character inputs.

<OTPField length={6}>
  <Label>Verification code</Label>
  <div className="flex items-center">
    <Group>
      <Input />
      <Input aria-label="Digit 2" />
      <Input aria-label="Digit 3" />
    </Group>
    <OTPFieldSeparator className="px-2 text-fg-muted">-</OTPFieldSeparator>
    <Group>
      <Input aria-label="Digit 4" />
      <Input aria-label="Digit 5" />
      <Input aria-label="Digit 6" />
    </Group>
  </div>
</OTPField>

Installation

npx shadcn@latest add @dotui/otp-field

Usage

Use OTPField with Group and the existing Input component to compose passcode slots.

import { OTPField } from '@/ui/otp-field'
import { Label } from '@/ui/field'
import { Group } from '@/ui/group'
import { Input } from '@/ui/input'
<OTPField length={6}>
  <Label>Verification code</Label>
  <Group>
    <Input />
    <Input aria-label="Digit 2" />
    <Input aria-label="Digit 3" />
    <Input aria-label="Digit 4" />
    <Input aria-label="Digit 5" />
    <Input aria-label="Digit 6" />
  </Group>
</OTPField>

Anatomy

OTPField wraps a Label, one or more Groups of single-character Input slots, and optional Description, FieldError, and OTPFieldSeparator parts. length sets how many slots render. Split the slots across Groups with an OTPFieldSeparator between them.

import { OTPField, OTPFieldSeparator } from '@/ui/otp-field'
import { Description, FieldError, Label } from '@/ui/field'
import { Group } from '@/ui/group'
import { Input } from '@/ui/input'
<OTPField length={6}>
  <Label />
  <Group>
    <Input />
  </Group>
  <OTPFieldSeparator />
  <Group>
    <Input />
  </Group>
  <Description />
  <FieldError />
</OTPField>

Value

The value is a string sized by length. Pass defaultValue for uncontrolled state, or value with onChange to control it.

const [value, setValue] = React.useState('')

<OTPField length={6} value={value} onChange={setValue}>
  {/* ... */}
</OTPField>

Validation

Mark the field isRequired, drive isInvalid to surface a FieldError alongside a Description, and set name for form submission. Use validationType to restrict input to "numeric" (default) or "alphanumeric".

<OTPField
  length={6}
  name="code"
  isInvalid={isInvalid}
  validationType="alphanumeric"
>
  <Label>Recovery code</Label>
  <Group>
    <Input />
    {/* ... */}
  </Group>
  <Description>Enter the code we sent you.</Description>
  <FieldError>Enter all six characters.</FieldError>
</OTPField>

Examples

Basic OTP Field

Verification Form

Enter the six-digit code sent to your email.

2FA Verification

Two-factor authentication

Enter the code from your authenticator app.

Email Verification

Verify your email

We sent a code to jane@acme.com

The code expires in 10 minutes.

API Reference

OTPField

An OTP field lets users enter a one-time passcode across multiple single-character inputs.

PropType
boolean
boolean
boolean
union
number
boolean
function
OTPValidationType
string
string
function

OTPFieldSeparator

A separator visually divides groups of inputs within the OTP field.

PropType
Orientation

Last updated on 7/22/2026