humanonlyweb/ui

OTP Input

A one-time code input, with a slot per character.

Markdown

Examples

Basic

complete fires once every slot is filled, so the code can be checked without a submit button.

Try 123456.

Copy code

Groups

Copy code

Letters and digits

Copy code

API

PropTypeDefault
label

Visible label, linked to the control.

string—
hint

Help text under the control, announced as its description.

string—
error

true marks the control invalid; a string also shows it as the message, replacing the hint.

string | boolean—
length

Number of characters in the code.

number6
type

"numeric" takes digits and shows the number pad; "alphanumeric" takes letters too.

"alphanumeric" | "numeric""numeric"
groupSize

Puts a separator after every this many slots, e.g. 3 for 123–456.

number—
optional

Appends the optional translation to the label.

booleanfalse
disabled

Disables the control.

booleanfalse
id

Id for the control; generated with useId() when omitted.

string—
modelValue

The code typed so far.

string""
EventPayload
complete

Every slot is filled, by typing, pasting or autofill.

[code: string]
update:modelValue

v-model:modelValue update.

[value: string]
SlotProps
separator

Content between groups. Defaults to a dash.

—

Styling

Parts
fieldfield-labelfield-optionalotpotp-inputotp-slototp-caretotp-separatorfield-message
States
data-field-errordata-otp-focuseddata-otp-disableddata-otp-activedata-otp-filleddata-field-tone

Accessibility

  • It's one native input with autocomplete="one-time-code", so codes from SMS and password managers fill in, and screen readers announce a single field.
  • Pasting a whole code fills every slot; spaces and dashes in it are dropped.
  • The slots are hidden from screen readers, which read the input's value instead.