Input OTP

One-time passcode input with grouped slots, built on input-otp.

<VStack className="w-full max-w-md" gap={2}>  <Label htmlFor="docs-otp-demo">Code</Label>  <InputOTP id="docs-otp-demo" 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></VStack>

Usage

import {
  InputOTP,
  InputOTPGroup,
  InputOTPSeparator,
  InputOTPSlot,
} from "@reva/ui";

Reva ships the shadcn/ui Input OTP API on top of input-otp. Use REGEXP_ONLY_DIGITS (and related helpers) from @reva/ui to restrict input.

Composition

Use the following composition to build an InputOTP:

InputOTP
├── InputOTPGroup
│   ├── InputOTPSlot (index 0)
│   ├── InputOTPSlot (index 1)
│   └── InputOTPSlot (index 2)
├── InputOTPSeparator
└── InputOTPGroup
    ├── InputOTPSlot (index 3)
    ├── InputOTPSlot (index 4)
    └── InputOTPSlot (index 5)

InputOTPSeparator is optional (between groups). For a single connected row of six slots, use one InputOTPGroup with six InputOTPSlot children (see Six digits below).

Examples

Sizes

Set controlSize on InputOTP to scale slot dimensions and typography (sm, default, lg, xl — slots use 32px / 40px / 44px / 48px sides, matching Input). This is named controlSize (not size) so the native size attribute on the underlying <input> remains available for character width if you need it.

<VStack className="w-full max-w-md" gap={4}>  <VStack gap={2}>    <Label htmlFor="docs-otp-size-sm">Small</Label>    <InputOTP controlSize="sm" id="docs-otp-size-sm" maxLength={6}>      <InputOTPGroup>        <InputOTPSlot index={0} />        <InputOTPSlot index={1} />        <InputOTPSlot index={2} />        <InputOTPSlot index={3} />        <InputOTPSlot index={4} />        <InputOTPSlot index={5} />      </InputOTPGroup>    </InputOTP>  </VStack>  <VStack gap={2}>    <Label htmlFor="docs-otp-size-default">Default</Label>    <InputOTP controlSize="default" id="docs-otp-size-default" maxLength={6}>      <InputOTPGroup>        <InputOTPSlot index={0} />        <InputOTPSlot index={1} />        <InputOTPSlot index={2} />        <InputOTPSlot index={3} />        <InputOTPSlot index={4} />        <InputOTPSlot index={5} />      </InputOTPGroup>    </InputOTP>  </VStack>  <VStack gap={2}>    <Label htmlFor="docs-otp-size-lg">Large (lg)</Label>    <InputOTP controlSize="lg" id="docs-otp-size-lg" maxLength={6}>      <InputOTPGroup>        <InputOTPSlot index={0} />        <InputOTPSlot index={1} />        <InputOTPSlot index={2} />        <InputOTPSlot index={3} />        <InputOTPSlot index={4} />        <InputOTPSlot index={5} />      </InputOTPGroup>    </InputOTP>  </VStack>  <VStack gap={2}>    <Label htmlFor="docs-otp-size-xl">Extra large (xl)</Label>    <InputOTP controlSize="xl" id="docs-otp-size-xl" maxLength={6}>      <InputOTPGroup>        <InputOTPSlot index={0} />        <InputOTPSlot index={1} />        <InputOTPSlot index={2} />        <InputOTPSlot index={3} />        <InputOTPSlot index={4} />        <InputOTPSlot index={5} />      </InputOTPGroup>    </InputOTP>  </VStack></VStack>

Six digits (typical 2FA)

Use one InputOTPGroup for a connected row (default). For spaced, separate cells, add gap on the group and per-slot border/radius classes as needed in your app.

<VStack className="w-full max-w-sm" gap={2}>  <Label htmlFor="docs-otp-6">Auth code</Label>  <InputOTP id="docs-otp-6" maxLength={6}>    <InputOTPGroup>      <InputOTPSlot index={0} />      <InputOTPSlot index={1} />      <InputOTPSlot index={2} />      <InputOTPSlot index={3} />      <InputOTPSlot index={4} />      <InputOTPSlot index={5} />    </InputOTPGroup>  </InputOTP></VStack>

Props

PartRole
InputOTPRoot; forwards to input-otp OTPInput (hidden input + context). Standard input props apply (maxLength, pattern, autoComplete, etc.). Optional controlSize: sm | default | lg | xl — scales slot boxes, separator icon, and caret (default: default).
InputOTPGroupHorizontal group for slots (default: connected borders).
InputOTPSlotindex (required) — slot position.
InputOTPSeparatorVisual separator between groups (minus icon).

Export REGEXP_ONLY_DIGITS, REGEXP_ONLY_CHARS, REGEXP_ONLY_DIGITS_AND_CHARS from @reva/ui for pattern on InputOTP.

On this page