Skip to main content

Installation

npm install @kuzenbo/core @kuzenbo/theme input-otp

Usage

import { InputOTP } from "@kuzenbo/core";

function App() {
  return (
    <InputOTP maxLength={6}>
      <InputOTP.Group>
        <InputOTP.Slot index={0} />
        <InputOTP.Slot index={1} />
        <InputOTP.Slot index={2} />
        <InputOTP.Slot index={3} />
        <InputOTP.Slot index={4} />
        <InputOTP.Slot index={5} />
      </InputOTP.Group>
    </InputOTP>
  );
}

Examples

Basic OTP Input

A 6-digit OTP input.
import { InputOTP } from "@kuzenbo/core";

function BasicExample() {
  return (
    <InputOTP maxLength={6}>
      <InputOTP.Group>
        <InputOTP.Slot index={0} />
        <InputOTP.Slot index={1} />
        <InputOTP.Slot index={2} />
        <InputOTP.Slot index={3} />
        <InputOTP.Slot index={4} />
        <InputOTP.Slot index={5} />
      </InputOTP.Group>
    </InputOTP>
  );
}

With Separator

Visually group digits with a separator.
import { InputOTP } from "@kuzenbo/core";

function SeparatorExample() {
  return (
    <InputOTP maxLength={6}>
      <InputOTP.Group>
        <InputOTP.Slot index={0} />
        <InputOTP.Slot index={1} />
        <InputOTP.Slot index={2} />
      </InputOTP.Group>
      <InputOTP.Separator />
      <InputOTP.Group>
        <InputOTP.Slot index={3} />
        <InputOTP.Slot index={4} />
        <InputOTP.Slot index={5} />
      </InputOTP.Group>
    </InputOTP>
  );
}

Controlled Value

Manage the OTP value with React state.
import { InputOTP } from "@kuzenbo/core";
import { useState } from "react";

function ControlledExample() {
  const [value, setValue] = useState("");

  return (
    <div className="grid gap-2">
      <InputOTP
        maxLength={6}
        value={value}
        onChange={setValue}
      >
        <InputOTP.Group>
          <InputOTP.Slot index={0} />
          <InputOTP.Slot index={1} />
          <InputOTP.Slot index={2} />
          <InputOTP.Slot index={3} />
          <InputOTP.Slot index={4} />
          <InputOTP.Slot index={5} />
        </InputOTP.Group>
      </InputOTP>
      <p className="text-muted-foreground text-sm">
        Value: {value || "(empty)"}
      </p>
    </div>
  );
}

Sizes

InputOTP supports size variants.
import { InputOTP } from "@kuzenbo/core";

function SizesExample() {
  return (
    <div className="grid gap-3">
      <InputOTP maxLength={6} size="xs">
        <InputOTP.Group>
          <InputOTP.Slot index={0} />
          <InputOTP.Slot index={1} />
          <InputOTP.Slot index={2} />
        </InputOTP.Group>
        <InputOTP.Separator />
        <InputOTP.Group>
          <InputOTP.Slot index={3} />
          <InputOTP.Slot index={4} />
          <InputOTP.Slot index={5} />
        </InputOTP.Group>
      </InputOTP>

      <InputOTP maxLength={6} size="sm">
        <InputOTP.Group>
          <InputOTP.Slot index={0} />
          <InputOTP.Slot index={1} />
          <InputOTP.Slot index={2} />
        </InputOTP.Group>
        <InputOTP.Separator />
        <InputOTP.Group>
          <InputOTP.Slot index={3} />
          <InputOTP.Slot index={4} />
          <InputOTP.Slot index={5} />
        </InputOTP.Group>
      </InputOTP>

      <InputOTP maxLength={6} size="md">
        <InputOTP.Group>
          <InputOTP.Slot index={0} />
          <InputOTP.Slot index={1} />
          <InputOTP.Slot index={2} />
        </InputOTP.Group>
        <InputOTP.Separator />
        <InputOTP.Group>
          <InputOTP.Slot index={3} />
          <InputOTP.Slot index={4} />
          <InputOTP.Slot index={5} />
        </InputOTP.Group>
      </InputOTP>

      <InputOTP maxLength={6} size="lg">
        <InputOTP.Group>
          <InputOTP.Slot index={0} />
          <InputOTP.Slot index={1} />
          <InputOTP.Slot index={2} />
        </InputOTP.Group>
        <InputOTP.Separator />
        <InputOTP.Group>
          <InputOTP.Slot index={3} />
          <InputOTP.Slot index={4} />
          <InputOTP.Slot index={5} />
        </InputOTP.Group>
      </InputOTP>

      <InputOTP maxLength={6} size="xl">
        <InputOTP.Group>
          <InputOTP.Slot index={0} />
          <InputOTP.Slot index={1} />
          <InputOTP.Slot index={2} />
        </InputOTP.Group>
        <InputOTP.Separator />
        <InputOTP.Group>
          <InputOTP.Slot index={3} />
          <InputOTP.Slot index={4} />
          <InputOTP.Slot index={5} />
        </InputOTP.Group>
      </InputOTP>
    </div>
  );
}

Pattern Validation

Restrict input to specific character patterns.
import { InputOTP } from "@kuzenbo/core";
import { REGEXP_ONLY_DIGITS } from "input-otp";

function PatternExample() {
  return (
    <InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS}>
      <InputOTP.Group>
        <InputOTP.Slot index={0} />
        <InputOTP.Slot index={1} />
        <InputOTP.Slot index={2} />
        <InputOTP.Slot index={3} />
        <InputOTP.Slot index={4} />
        <InputOTP.Slot index={5} />
      </InputOTP.Group>
    </InputOTP>
  );
}

Props

InputOTP

InputOTP extends input-otp OTPInput props.
maxLength
number
required
Maximum number of characters (number of slots).
value
string
Controlled value of the OTP input.
onChange
(value: string) => void
Callback fired when the value changes.
onComplete
(value: string) => void
Callback fired when all slots are filled.
pattern
string
Regular expression pattern to restrict allowed characters.
size
string
default:"md"
Size variant of the OTP input.Options: "xs" | "sm" | "md" | "lg" | "xl"
disabled
boolean
default:"false"
When true, disables the OTP input.
autoFocus
boolean
default:"false"
When true, automatically focuses the first slot on mount.
pushPasswordManagerStrategy
string
Strategy for handling password manager autofill.
className
string
Additional CSS classes for the input element.
containerClassName
string
Additional CSS classes for the container.
children
ReactNode
required
InputOTP.Group and InputOTP.Separator components.

Subcomponents

InputOTP.Group

Container for a group of OTP slots.
<InputOTP.Group>
  <InputOTP.Slot index={0} />
  <InputOTP.Slot index={1} />
  <InputOTP.Slot index={2} />
</InputOTP.Group>

InputOTP.Slot

An individual character slot.
index
number
required
Zero-based index of this slot.

InputOTP.Separator

A visual separator between groups.
<InputOTP.Separator />

TypeScript

import type {
  InputOTPProps,
  InputOTPGroupProps,
  InputOTPSlotProps,
  InputOTPSeparatorProps,
} from "@kuzenbo/core";

const CustomInputOTP = (props: InputOTPProps) => {
  return <InputOTP {...props} />;
};

Accessibility

  • InputOTP uses semantic input elements
  • Supports keyboard navigation between slots
  • Auto-advances to next slot on input
  • Backspace moves to previous slot
  • Paste support for filling multiple slots
  • Disabled state prevents all interactions
  • Properly announces to screen readers

Build docs developers (and LLMs) love