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
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | undefined | Unique element ID for accessibility labels and DOM querying. |
name | string | undefined | Form control name submitted with standard HTML forms / FormData. |
length | number | 6 | Number of OTP digit input slots. |
type | "numeric" | "alpha" | "alphanumeric" | "numeric" | Allowed input validation pattern. |
value | string | undefined | Controlled input value. |
defaultValue | string | "" | Initial uncontrolled input value. |
mask | boolean | false | Mask input characters using password type. |
autoFocus | boolean | false | Automatically focus on the first input slot on render. |
disabled | boolean | false | Disables all inputs and resend controls. |
readOnly | boolean | false | Prevents editing input content. |
required | boolean | false | Marks the field as required for native HTML form validation. |
error | boolean | false | Indicates an invalid state visually. Auto-switches to the error color palette unless `color` is explicitly set. |
errorMessage | string | undefined | Error 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. |
style | OtpInputSlotStyle | undefined | Slot-based style overrides keyed by `Bui.*` slot names. See the slots reference below. |
ariaLabel | string | "One-time password" | Accessible label for screen readers. |
autoComplete | boolean | true | Enable SMS autofill support on mobile. |
separator | ReactNode | undefined | Custom visual separator rendered between input slots. |
spacing | number | 8 | Gap spacing in pixels between input slots. |
inputWidth | number | 40 | Pixel width for individual input fields. |
inputHeight | number | 48 | Pixel height for individual input fields. |
showResend | boolean | false | Displays the resend action/countdown timer block. |
resendTimeout | number | 60 | Countdown interval in seconds between allowed resend triggers. |
resendLabel | string | "Resend Code" | Text displayed on the clickable resend action button. |
resendTimerLabel | string | ((seconds: number) => string) | "Resend code in {time}s" | Text template or callback for active timer display. |
maxResendAttempts | number | undefined | Maximum allowed resend triggers before disabling action. |
onFocus | (e: FocusEvent<HTMLDivElement>) => void | undefined | Callback fired when the component receives focus. |
onBlur | (e: FocusEvent<HTMLDivElement>) => void | undefined | Callback fired when the component loses focus. |
onChange | (value: string) => void | undefined | Triggered when any slot value changes. |
onComplete | (value: string) => void | undefined | Triggered when all inputs are completely filled. |
onEnter | (value: string) => void | undefined | Triggered when Enter key is pressed after full code completion. |
onResend | () => void | undefined | Callback triggered when resend action button is clicked. |
onMaxResendAttemptsExceeded | () => void | undefined | Callback triggered when resend attempt threshold is reached. |
OtpInput Style Slots
| Slot | Description |
|---|---|
Bui.root | Container wrapper around all input slots. |
Bui.input | Individual input field (default state). |
Bui.inputFocus | Input field while focused. |
Bui.inputDisabled | Input field while disabled. |
Bui.placeholder | Empty-input placeholder color/typography. Adapts automatically per `variant`. |
Bui.separator | Separator element between inputs. |
Bui.errorMessage | Error message displayed below the inputs. |
Bui.resendContainer | Container wrapping the resend button and timer text. |
Bui.resendButton | Resend button, applied as a fallback for both enabled/disabled states. |
Bui.resendButtonEnabled | Resend button when clickable. Overrides `Bui.resendButton`. |
Bui.resendButtonDisabled | Resend button while the countdown is active. |
Bui.resendText | Resend timer text, applied as a fallback for both states. |
Bui.resendTextDisabled | Resend timer text while counting down. Overrides `Bui.resendText`. |