Forms

InputOTP

A one-time password input component for verification codes and secure authentication

Completeness: behavior-required

The stylesheet is only the visible half of this component. It also needs a keyboard map, focus managed across more than one element, ARIA attributes that point at other nodes, and [data-*] attributes that only running code sets — so a CSS-only port will not reproduce it. Use @blakeui/react, or read the interaction contract from the MCP server with get_component_behavior("InputOTP") and build the behaviour yourself.

Import

import { InputOTP } from '@blakeui/react';

Usage

We've sent a code to a****@gmail.com

Didn't receive a code?

Resend
import {InputOTP, Label, Link} from "@blakeui/react";

export function Basic() {
  return (
    <div className="flex w-[280px] flex-col gap-2">

Anatomy

Import the InputOTP component and access all parts using dot notation.

import { InputOTP } from '@blakeui/react';

export default () => (
  <InputOTP maxLength={6}>
    <InputOTP.Group>
      <InputOTP.Slot index={0} />
      <InputOTP.Slot index={1} />
      {/* ...rest of the slots */}
    </InputOTP.Group>
    <InputOTP.Separator />
    <InputOTP.Group>
      <InputOTP.Slot index={3} />
      {/* ...rest of the slots */}
    </InputOTP.Group>
  </InputOTP>
)

InputOTP is built on top of input-otp by @guilherme_rodz, providing a flexible and accessible foundation for OTP input components.

Four Digits

import {InputOTP, Label} from "@blakeui/react";

export function FourDigits() {
  return (
    <div className="flex w-[280px] flex-col gap-2">

Disabled State

Code verification is currently disabled
import {Description, InputOTP, Label} from "@blakeui/react";

export function Disabled() {
  return (
    <div className="flex w-[280px] flex-col gap-2">

With Pattern

Use the pattern prop to restrict input to specific characters. blakeUI exports common patterns like REGEXP_ONLY_CHARS and REGEXP_ONLY_DIGITS.

Only alphabetic characters are allowed
import {Description, InputOTP, Label, REGEXP_ONLY_CHARS} from "@blakeui/react";

export function WithPattern() {
  return (
    <div className="flex w-[280px] flex-col gap-2">

Controlled

Control the value to synchronize with state, clear the input, or implement custom validation.

Enter a 6-digit code
"use client";

import {Description, InputOTP, Label} from "@blakeui/react";
import React from "react";

With Validation

Use isInvalid together with validation messages to surface errors.

Hint: The code is 123456
Invalid code. Please try again.
"use client";

import {Button, Description, Form, InputOTP, Label} from "@blakeui/react";
import React from "react";

On Complete

Use the onComplete callback to trigger actions when all slots are filled.

"use client";

import {Button, Form, InputOTP, Label, Spinner} from "@blakeui/react";
import React from "react";

Form Example

A complete two-factor authentication form with validation and submission.

Enter the 6-digit code from your authenticator app

Having trouble?

Use backup code
"use client";

import {Button, Description, Form, InputOTP, Label, Link, Spinner} from "@blakeui/react";
import React from "react";

Variants

The InputOTP component supports two visual variants:

  • primary (default) - Standard styling with shadow, suitable for most use cases
  • secondary - Lower emphasis variant without shadow, suitable for use in Surface components
import {InputOTP, Label} from "@blakeui/react";

export function Variants() {
  return (
    <div className="flex flex-col gap-6">

In Surface

When used inside a Surface component, use variant="secondary" to apply the lower emphasis variant suitable for surface backgrounds.

We've sent a code to a****@gmail.com

Didn't receive a code?

Resend
import {InputOTP, Label, Link, Surface} from "@blakeui/react";

export function OnSurface() {
  return (
    <Surface className="flex w-full flex-col gap-2 rounded-3xl p-6">

Styling

Passing Tailwind CSS classes

import {InputOTP, Label} from '@blakeui/react';

function CustomInputOTP() {
  return (
    <div className="flex flex-col gap-2">
      <Label className="text-sm font-semibold">Enter verification code</Label>
      <InputOTP
        className="gap-3"
        containerClassName="gap-4"
        maxLength={6}
      >
        <InputOTP.Group className="gap-3">
          <InputOTP.Slot
            className="size-12 rounded-lg border-2 text-lg font-bold"
            index={0}
          />
          <InputOTP.Slot
            className="size-12 rounded-lg border-2 text-lg font-bold"
            index={1}
          />
          <InputOTP.Slot
            className="size-12 rounded-lg border-2 text-lg font-bold"
            index={2}
          />
        </InputOTP.Group>
        <InputOTP.Separator className="bg-border h-1 w-2 rounded-full" />
        <InputOTP.Group className="gap-3">
          <InputOTP.Slot
            className="size-12 rounded-lg border-2 text-lg font-bold"
            index={3}
          />
          <InputOTP.Slot
            className="size-12 rounded-lg border-2 text-lg font-bold"
            index={4}
          />
          <InputOTP.Slot
            className="size-12 rounded-lg border-2 text-lg font-bold"
            index={5}
          />
        </InputOTP.Group>
      </InputOTP>
    </div>
  );
}

Customizing the component classes

To customize the InputOTP component classes, you can use the @layer components directive.
Learn more.

A worked example is in Styling.

blakeUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.

CSS Classes

The InputOTP component uses these CSS classes (View source styles):

Base Classes

  • .input-otp - Base container
  • .input-otp__container - Inner container from input-otp library
  • .input-otp__group - Group of slots
  • .input-otp__slot - Individual input slot
  • .input-otp__slot-value - The character inside a slot
  • .input-otp__caret - Blinking caret indicator
  • .input-otp__separator - Visual separator between groups

State Classes

  • .input-otp__slot[data-active="true"] - Currently active slot
  • .input-otp__slot[data-filled="true"] - Slot with a character
  • .input-otp__slot[data-disabled="true"] - Disabled slot
  • .input-otp__slot[data-invalid="true"] - Invalid slot
  • .input-otp__container[data-disabled="true"] - Disabled container

Interactive States

The component supports both CSS pseudo-classes and data attributes for flexibility:

  • Hover: :hover or [data-hovered="true"] on slot
  • Active: [data-active="true"] on slot (currently focused)
  • Filled: [data-filled="true"] on slot (contains a character)
  • Disabled: [data-disabled="true"] on container and slots
  • Invalid: [data-invalid="true"] on slots

API Reference

InputOTP Props

InputOTP is built on top of the input-otp library with additional features.

Base Props

PropTypeDefaultDescription
maxLengthnumber-Required. Number of input slots.
valuestring-Controlled value (uncontrolled if not provided).
onChange(value: string) => void-Handler called when the value changes.
onComplete(value: string) => void-Handler called when all slots are filled.
classNamestring-Additional CSS classes for the container.
containerClassNamestring-CSS classes for the inner container.
variant"primary" | "secondary""primary"Visual variant of the component. primary is the default style with shadow. secondary is a lower emphasis variant without shadow, suitable for use in surfaces.
childrenReact.ReactNode-InputOTP.Group, InputOTP.Slot, and InputOTP.Separator components.

Validation Props

PropTypeDefaultDescription
isDisabledbooleanfalseWhether the input is disabled.
isInvalidbooleanfalseWhether the input is in an invalid state.
validationErrorsstring[]-Server-side or custom validation errors.
validationDetailsValidityState-HTML5 validation details.

Input Props

PropTypeDefaultDescription
patternstring-Regex pattern for allowed characters (e.g., REGEXP_ONLY_DIGITS).
textAlign'left' | 'center' | 'right''left'Text alignment within slots.
inputMode'numeric' | 'text' | 'decimal' | 'tel' | 'search' | 'email' | 'url''numeric'Virtual keyboard type on mobile devices.
placeholderstring-Placeholder text for empty slots.
pasteTransformer(text: string) => string-Transform pasted text (e.g., remove hyphens).

Form Props

PropTypeDefaultDescription
namestring-Name attribute for form submission.
autoFocusboolean-Whether to focus the first slot on mount.

InputOTP.Group Props

PropTypeDefaultDescription
classNamestring-Additional CSS classes for the group.
childrenReact.ReactNode-InputOTP.Slot components.

InputOTP.Slot Props

PropTypeDefaultDescription
indexnumber-Required. Zero-based index of the slot.
classNamestring-Additional CSS classes for the slot.

InputOTP.Separator Props

PropTypeDefaultDescription
classNamestring-Additional CSS classes for the separator.

Exported Patterns

blakeUI re-exports common regex patterns from input-otp for convenience:

import { REGEXP_ONLY_DIGITS, REGEXP_ONLY_CHARS, REGEXP_ONLY_DIGITS_AND_CHARS } from '@blakeui/react';

// Use with pattern prop
<InputOTP pattern={REGEXP_ONLY_DIGITS} maxLength={6}>
  {/* ... */}
</InputOTP>
  • REGEXP_ONLY_DIGITS - Only numeric characters (0-9)
  • REGEXP_ONLY_CHARS - Only alphabetic characters (a-z, A-Z)
  • REGEXP_ONLY_DIGITS_AND_CHARS - Alphanumeric characters (0-9, a-z, A-Z)

On this page