InputOtp
Overview
A one-time-password (OTP / verification code) input built around a real native input. It keeps the robust selection, paste, and mobile autofill behavior of vue-input-otp while exposing a default VeanUI presentation and a fully custom scoped slot. Use it for SMS codes, email verification codes, two-factor authentication, or any fixed-length code entry.
Usage
Features
- 📏 6 sizes: xs, sm, md, lg, xl, 2xl
- 🔤 Real native input overlay — native selection, paste, and mobile autofill / password-manager behavior
- 📐
aligncontrol: start / center / end - 🎨 Fully custom
defaultslot per character, with placeholder chars and fake caret - 🔢
maxlengthclamping pluspatternvalidation (double-layerbeforeinput+ rollback) - 📋
pasteTransformerfor normalizing pasted input, and acompleteevent when full - 🔐 Password-manager badge detection (disable via
pushPasswordManagerStrategy) - ♿ Full accessibility support —
aria-label,inputmode, axe-clean
Demos
Basic
Value: -
Placeholder
Custom Slot
API
Aria Layer
5InputOtp
Props
| Prop | Type | Default | Description |
|---|---|---|---|
class | ClassValue | — | Root class. |
size | ThemeSize | — | Visual size of the component. |
align | Align | — | Align. |
ui | Partial<InputOtpUi> | — | Per-slot class overrides for the component. |
id | string | — | The id of the native input element. |
autocomplete | string | — | Autocomplete hint passed to the native input. |
autofocus | boolean | — | Whether the input should be focused on mount. |
disabled | boolean | — | Whether the input is disabled. |
minlength | number | — | Minimum length forwarded to the native input. |
placeholder | string | — | Placeholder characters used by the visual slots. |
readonly | boolean | — | Whether the input is readonly. |
ariaLabel | string | — | Accessible label forwarded to the native input. |
modelValue | string | — | The controlled value of the OTP input. |
defaultValue | string | — | The uncontrolled default value of the OTP input. |
maxlength | number | — | The number of OTP slots. |
inputmode | InputOtpInputMode | — | Virtual keyboard mode for mobile devices. |
pattern | string | RegExp | — | Pattern used to validate the whole OTP value. |
pushPasswordManagerStrategy | InputOtpPushPasswordManagerStrategy | — | Strategy used to avoid overlapping password manager badges. |
pasteTransformer | ((pasted: string) => string) | — | Transform pasted content before it is inserted. |
name | string | — | The name of the field. Submitted with its owning form as part of a name/value pair. |
required | boolean | — | When `true`, indicates that the user must set the value before the owning form can be submitted. |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
update:modelValue | string | Emitted when the model value changes. |
complete | string | Emitted when complete occurs. |
input | string | Emitted when input occurs. |
change | Event | Emitted when change occurs. |
select | Event | Emitted when select occurs. |
focus | FocusEvent | Emitted when focus occurs. |
blur | FocusEvent | Emitted when blur occurs. |
mouseover | MouseEvent | Emitted when mouseover occurs. |
mouseleave | MouseEvent | Emitted when mouseleave occurs. |
paste | ClipboardEvent | Emitted when paste occurs. |
Slots
| Slot Name | Parameters | Description |
|---|---|---|
default | InputOtpRootSlotProps | Custom content for the default slot. |
InputOtpCompact
Props
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | — | The id of the native input element. |
autocomplete | string | — | Autocomplete hint passed to the native input. |
autofocus | boolean | — | Whether the input should be focused on mount. |
disabled | boolean | — | Whether the input is disabled. |
minlength | number | — | Minimum length forwarded to the native input. |
placeholder | string | — | Placeholder characters used by the visual slots. |
readonly | boolean | — | Whether the input is readonly. |
ariaLabel | string | — | Accessible label forwarded to the native input. |
modelValue | string | — | The controlled value of the OTP input. |
defaultValue | string | — | The uncontrolled default value of the OTP input. |
maxlength | number | — | The number of OTP slots. |
inputmode | InputOtpInputMode | — | Virtual keyboard mode for mobile devices. |
pattern | string | RegExp | — | Pattern used to validate the whole OTP value. |
pushPasswordManagerStrategy | InputOtpPushPasswordManagerStrategy | — | Strategy used to avoid overlapping password manager badges. |
pasteTransformer | ((pasted: string) => string) | — | Transform pasted content before it is inserted. |
name | string | — | The name of the field. Submitted with its owning form as part of a name/value pair. |
required | boolean | — | When `true`, indicates that the user must set the value before the owning form can be submitted. |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
update:modelValue | string | Emitted when the model value changes. |
complete | string | Emitted when complete occurs. |
input | string | Emitted when input occurs. |
change | Event | Emitted when change occurs. |
select | Event | Emitted when select occurs. |
focus | FocusEvent | Emitted when focus occurs. |
blur | FocusEvent | Emitted when blur occurs. |
mouseover | MouseEvent | Emitted when mouseover occurs. |
mouseleave | MouseEvent | Emitted when mouseleave occurs. |
paste | ClipboardEvent | Emitted when paste occurs. |
Slots
| Slot Name | Parameters | Description |
|---|---|---|
default | InputOtpRootSlotProps | Custom content for the default slot. |
InputOtpInput
InputOtpPositioner
InputOtpRoot
Props
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | — | The id of the native input element. |
autocomplete | string | — | Autocomplete hint passed to the native input. |
autofocus | boolean | — | Whether the input should be focused on mount. |
disabled | boolean | — | Whether the input is disabled. |
minlength | number | — | Minimum length forwarded to the native input. |
placeholder | string | — | Placeholder characters used by the visual slots. |
readonly | boolean | — | Whether the input is readonly. |
ariaLabel | string | — | Accessible label forwarded to the native input. |
modelValue | string | — | The controlled value of the OTP input. |
defaultValue | string | — | The uncontrolled default value of the OTP input. |
maxlength | number | — | The number of OTP slots. |
inputmode | InputOtpInputMode | — | Virtual keyboard mode for mobile devices. |
pattern | string | RegExp | — | Pattern used to validate the whole OTP value. |
pushPasswordManagerStrategy | InputOtpPushPasswordManagerStrategy | — | Strategy used to avoid overlapping password manager badges. |
pasteTransformer | ((pasted: string) => string) | — | Transform pasted content before it is inserted. |
name | string | — | The name of the field. Submitted with its owning form as part of a name/value pair. |
required | boolean | — | When `true`, indicates that the user must set the value before the owning form can be submitted. |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
update:modelValue | string | Emitted when the model value changes. |
complete | string | Emitted when complete occurs. |
input | string | Emitted when input occurs. |
change | Event | Emitted when change occurs. |
select | Event | Emitted when select occurs. |
focus | FocusEvent | Emitted when focus occurs. |
blur | FocusEvent | Emitted when blur occurs. |
mouseover | MouseEvent | Emitted when mouseover occurs. |
mouseleave | MouseEvent | Emitted when mouseleave occurs. |
paste | ClipboardEvent | Emitted when paste occurs. |
Notes
Architecture and benchmark differences
VeanUI splits input-otp into an Aria layer (@vean/aria/input-otp) that owns the transparent input overlay, selection mirroring, and validation, and a styled layer (@vean/ui) that owns variants and UnoCSS classes. The Aria InputOtpCompact composes InputOtpRoot / InputOtpPositioner / InputOtpInput. This is a port of the vue-input-otp approach used by reka-ui and shadcn, with Vean’s size variants and align states as differentiators.
| Capability | VeanUI | reka-ui InputOtp | shadcn InputOTP | Element Plus |
|---|---|---|---|---|
| Aria/styled split | ✅ | — | — | — |
| Controlled / uncontrolled | ✅ | ✅ | ✅ | — |
maxlength / pattern | ✅ | ✅ | ✅ | — |
| Real input transparent overlay | ✅ | ✅ | ✅ | — |
| Selection mirroring | ✅ | ✅ | ✅ | — |
| Paste transformer | ✅ | ✅ | ✅ | — |
| Password-manager badge handling | ✅ | ✅ | ✅ | — |
| iOS autofill | ✅ | ✅ | ✅ | — |
complete event | ✅ | ✅ | ✅ | — |
| Size variants (xs…2xl) | ✅ | — | — | — |
align states | ✅ | ✅ | ✅ | — |
| Custom visual slot (fake caret) | ✅ | ✅ | ✅ | — |
Cautions
maxlengthis required — it drives the number of rendered characters.- The
aria-labelprop is declared asariaLabel(camelCase); both kebab-case attributes and camelCase props work, and it falls back to the localized defaultOne-time password. - Locale-aware default
aria-labelandcontextmenuhandling are tracked as enhancement backlog.
FAQ
How do I customize the character cells?
Use the default slot. Each character receives char, placeholderChar, isActive, and hasFakeCaret so you can render boxes, separators, or custom carets.
How do I trigger an action when the code is complete?
Listen for the complete event, emitted once all cells are filled.
How do I restrict what characters can be entered?
Pass maxlength for length and pattern for a per-character validation regex. Invalid input is rejected by beforeinput interception and rolled back on input.
How do I make the OTP usable in a native form?
Pass name — the transparent input carries the value and participates in native form submission and autofill.