HomeBytesheetsUI TemplatesUI ToolsRoad MapsStack DiscussionByte Camp
BytesUIv0.5.3
⌘K

OtpInput

Accessible verification code input supporting controlled/uncontrolled state, auto-focus, masking, and resend timers.

Quick Usage

Basic usage of `OtpInput` with handling completion callback. Remember to wrap your app in `ThemeProvider` (see the Theming page) so `color` and `variant` resolve correctly.

import React from 'react';
import { OtpInput } from '@bytesui/react';

export default function OtpExample() {
  return (
    <OtpInput
      length={6}
      type="numeric"
      autoFocus
      onComplete={(code) => console.log('OTP Submitted:', code)}
    />
  );
}

Interactive Demo

Test interactive configurations of OtpInput live.

Custom Styling Showcase

Slot styles let you reshape `OtpInput` entirely. Stack multiple styled instances on the same page to compare looks — circular pills, underline-only, and soft rounded cards.

Color & Variant

`OtpInput` accepts `color` (one of the 8 semantic colors) and `variant` (`solid` | `outlined` | `soft` | `plain`). Defaults are `color="primary"` and `variant="outlined"`. When `error` is `true` and no explicit `color` is set, the error palette is used automatically.

import React from 'react';
import { OtpInput } from '@bytesui/react';

export default function OtpColorVariantExample() {
  return (
    <>
      <OtpInput length={4} color="secondary" variant="solid" />
      <OtpInput length={4} color="success" variant="soft" />
      <OtpInput length={4} color="tertiary" variant="plain" />
      {/* error=true auto-switches to the error palette when color is left as default */}
      <OtpInput length={4} error errorMessage="Invalid code" />
    </>
  );
}

Slot Styling

Use the `style` prop with `Bui.*` slot keys to override specific parts of the component without extra CSS. `Bui.placeholder` controls the empty-input placeholder color/typography and automatically adapts per `variant` unless overridden.

import React from 'react';
import { OtpInput } from '@bytesui/react';

export default function OtpSlotStylingExample() {
  return (
    <OtpInput
      length={6}
      color="secondary"
      style={{
        'Bui.root': { gap: '12px' },
        'Bui.input': { borderRadius: '10px', fontWeight: '700' },
        'Bui.inputFocus': { borderWidth: '2px' },
        'Bui.placeholder': { color: '#94a3b8', opacity: 0.6 },
        'Bui.errorMessage': { color: '#dc2626', fontSize: '13px' },
        'Bui.resendButtonEnabled': { color: '#0ea5e9', fontWeight: '600' },
        'Bui.resendTextDisabled': { color: '#6b7280' }
      }}
      showResend
      resendTimeout={30}
    />
  );
}

Resend Timer Usage

Using resend timer controls, max attempt limits, and error handling.

import React from 'react';
import { OtpInput } from '@bytesui/react';

export default function ResendOtpExample() {
  return (
    <OtpInput
      length={4}
      showResend
      resendTimeout={30}
      maxResendAttempts={3}
      onResend={() => console.log('Resending code...')}
      onMaxResendAttemptsExceeded={() => alert('Max resend attempts reached!')}
    />
  );
}

OtpInput API

PropTypeDefaultDescription
idstringundefinedUnique element ID for accessibility labels and DOM querying.
namestringundefinedForm control name submitted with standard HTML forms / FormData.
lengthnumber6Number of OTP digit input slots.
type"numeric" | "alpha" | "alphanumeric""numeric"Allowed input validation pattern.
valuestringundefinedControlled input value.
defaultValuestring""Initial uncontrolled input value.
maskbooleanfalseMask input characters using password type.
autoFocusbooleanfalseAutomatically focus on the first input slot on render.
disabledbooleanfalseDisables all inputs and resend controls.
readOnlybooleanfalsePrevents editing input content.
requiredbooleanfalseMarks the field as required for native HTML form validation.
errorbooleanfalseIndicates an invalid state visually. Auto-switches to the error color palette unless `color` is explicitly set.
errorMessagestringundefinedError text displayed beneath input slots.
color'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'error' | 'neutral' | 'info'"primary"Semantic color of the input, resolved from the active theme.
variant'solid' | 'outlined' | 'soft' | 'plain'"outlined"Visual style variant of the input.
styleOtpInputSlotStyleundefinedSlot-based style overrides keyed by `Bui.*` slot names. See the slots reference below.
ariaLabelstring"One-time password"Accessible label for screen readers.
autoCompletebooleantrueEnable SMS autofill support on mobile.
separatorReactNodeundefinedCustom visual separator rendered between input slots.
spacingnumber8Gap spacing in pixels between input slots.
inputWidthnumber40Pixel width for individual input fields.
inputHeightnumber48Pixel height for individual input fields.
showResendbooleanfalseDisplays the resend action/countdown timer block.
resendTimeoutnumber60Countdown interval in seconds between allowed resend triggers.
resendLabelstring"Resend Code"Text displayed on the clickable resend action button.
resendTimerLabelstring | ((seconds: number) => string)"Resend code in {time}s"Text template or callback for active timer display.
maxResendAttemptsnumberundefinedMaximum allowed resend triggers before disabling action.
onFocus(e: FocusEvent<HTMLDivElement>) => voidundefinedCallback fired when the component receives focus.
onBlur(e: FocusEvent<HTMLDivElement>) => voidundefinedCallback fired when the component loses focus.
onChange(value: string) => voidundefinedTriggered when any slot value changes.
onComplete(value: string) => voidundefinedTriggered when all inputs are completely filled.
onEnter(value: string) => voidundefinedTriggered when Enter key is pressed after full code completion.
onResend() => voidundefinedCallback triggered when resend action button is clicked.
onMaxResendAttemptsExceeded() => voidundefinedCallback triggered when resend attempt threshold is reached.

OtpInput Style Slots

SlotDescription
Bui.rootContainer wrapper around all input slots.
Bui.inputIndividual input field (default state).
Bui.inputFocusInput field while focused.
Bui.inputDisabledInput field while disabled.
Bui.placeholderEmpty-input placeholder color/typography. Adapts automatically per `variant`.
Bui.separatorSeparator element between inputs.
Bui.errorMessageError message displayed below the inputs.
Bui.resendContainerContainer wrapping the resend button and timer text.
Bui.resendButtonResend button, applied as a fallback for both enabled/disabled states.
Bui.resendButtonEnabledResend button when clickable. Overrides `Bui.resendButton`.
Bui.resendButtonDisabledResend button while the countdown is active.
Bui.resendTextResend timer text, applied as a fallback for both states.
Bui.resendTextDisabledResend timer text while counting down. Overrides `Bui.resendText`.