S
Special Field

OTP Input

One-time password input with individual digit boxes for verification codes.

stable
otp verification code pin

Interactive demo of OTP input field

Enter the 6-digit code sent to your email

/**
 * OTP Field Demo - Interactive examples of OTP input fields
 */

import { Form, FormBuilder } from '@saastro/forms';

import { FormProvider } from '@/components/FormProvider';
import { TooltipProvider } from '@/components/ui/tooltip';

const config = FormBuilder.create('otp-demo')
  .layout('manual')
  .columns(12)
  .addField('verificationCode', (f) =>
    f
      .type('otp')
      .label('Verification Code')
      .helperText('Enter the 6-digit code sent to your email')
      .required('Verification code is required')
      .columns({ default: 12 }),
  )
  .addStep('main', ['verificationCode'])
  .build();

export default function OtpDemo() {
  const handleSubmit = (data: Record<string, unknown>) => {
    console.log('Form submitted:', data);
    alert('Form submitted! Check console for data.');
  };

  return (
    <TooltipProvider>
      <FormProvider>
        <Form config={config} onSubmit={handleSubmit} className="space-y-4" />
      </FormProvider>
    </TooltipProvider>
  );
}

Overview

The OTP (One-Time Password) field provides a series of input boxes for entering verification codes. It’s commonly used for 2FA, phone verification, and email confirmation flows.

Usage

Basic OTP Input

import { FormBuilder } from '@saastro/forms';

const config = FormBuilder.create('verification')
  .addField('code', (f) =>
    f
      .type('otp')
      .label('Verification Code')
      .helperText('Enter the 6-digit code sent to your email')
      .required('Verification code is required'),
  )
  .addStep('main', ['code'])
  .build();

With Custom Length

The default OTP length is 6 digits. You can configure this via the component registry.

JSON Configuration

{
  "type": "otp",
  "label": "Verification Code",
  "helperText": "Enter the 6-digit code sent to your phone",
  "schema": { "required": true }
}

Props

PropTypeDefaultDescription
type'otp'-Field type (required)
labelstring-Label text
helperTextstring-Help text below input
columnsPartial<Record<Breakpoint, number>>-Grid columns by breakpoint
disabledboolean | function | ConditionGroupfalseDisable the field
hiddenboolean | function | ConditionGroup | ResponsivefalseHide the field

Validation

Required Code

.addField('verificationCode', (f) =>
  f.type('otp')
    .label('Enter Code')
    .required('Please enter the verification code')
)

With Pattern Validation

.addField('pin', (f) =>
  f.type('otp')
    .label('PIN')
    .required()
    .regex('^[0-9]{6}$', 'PIN must be 6 digits')
)

Features

  • Auto-focus: Automatically focuses the first empty box
  • Auto-advance: Moves to next box after input
  • Paste support: Handles pasted codes correctly
  • Backspace handling: Moves back on delete

Use Cases

  1. Email verification: Confirm email ownership
  2. Phone verification: SMS code entry
  3. Two-factor authentication: TOTP codes
  4. Payment confirmation: Transaction PINs

Styling

Custom Classes

.addField('code', (f) =>
  f.type('otp')
    .label('Verification Code')
    .required()
    .classNames({
      wrapper: 'bg-muted/30 p-6 rounded-lg text-center',
      input: 'border-2 border-primary/20',
      label: 'text-lg font-semibold',
      helper: 'text-muted-foreground text-sm',
      error: 'text-destructive text-sm',
    })
)

Responsive Layout

.addField('pin', (f) =>
  f.type('otp')
    .label('PIN')
    .columns({ default: 12, md: 6 })
)

JSON Styling

{
  "type": "otp",
  "label": "Verification Code",
  "wrapper_className": "bg-muted/30 p-6 rounded-lg text-center",
  "input_className": "border-2 border-primary/20",
  "label_className": "text-lg font-semibold",
  "columns": { "default": 12, "md": 6 }
}

Accessibility

  • Built on input-otp library
  • Keyboard navigation between boxes
  • Screen reader support
  • Focus visible states
  • Proper ARIA labels