Docs·OTP Input

OTP Input

Accessible verification-code slots built on Base UI with grouped separators, masking, validation states, and reduced-motion support.

Installation

$pnpm dlx shadcn@latest add @spiderui/otp-input

Usage

API Reference

PropTypeDefault
lengthNumber of input slots, clamped from 1 to 12.
number6
valueControlled OTP value.
string—
defaultValueInitial value for an uncontrolled OTP input.
string—
onValueChangeCalled whenever the normalized value changes.
(value: string) => void—
onValueCompleteCalled when every slot is filled.
(value: string) => void—
validationTypeCharacters accepted by the field.
"numeric" | "alphanumeric" | "alpha""numeric"
maskReplace entered characters with dots.
booleanfalse
separatorAfterSlot positions where OTPInputSlots inserts separators.
number | readonly number[]—
sizeSlot size preset.
"sm" | "default""default"
invalidApply invalid styling and accessibility state.
booleanfalse
labelAccessible field label.
ReactNode—
descriptionHelp text linked to the field.
ReactNode—
errorMessageAccessible error text that also marks the field invalid.
ReactNode—

Click on the icon in the top right of the example preview to view the source code for specific variants.

Keep in mind

This component is inspired by various open-source projects and patterns. Please verify licenses and implementation details before using in production.

Have any questions?
Contact on@ctrlcat0x

Enter the code sent to your device.

import { OTPInput, OTPInputSlots } from "@/components/ui/otp-input"
export function VerificationCode() {
  return (
    <OTPInput
      length={6}
      label="Verification code"
      description="Enter the code sent to your device."
      onValueComplete={(code) => console.log(code)}
    >
      <OTPInputSlots separatorAfter={3} />
    </OTPInput>
  )
}