Skip to contents

OTP Field

A one-time password input composed of individual character slots.

Enter the 6-character code we sent to your device.

Usage guidelines

Anatomy

Import the component and assemble its parts:

Anatomy

Examples

Labeling an OTP field

Pass an id to <OTPField.Root> and use a native <label> with a matching for. Let the first input use the field label, and add aria-label to the remaining inputs so assistive technology can announce which slot is focused.

Optionally, add aria-describedby when supporting text should be announced with the field.

OTP Field with a native label and description

Form integration

Use Field to handle label associations and form integration:

Using OTP Field in a form

Pass autoSubmit to submit the owning form automatically when all slots are filled, or use onValueComplete to react to completion without submitting.

Alphanumeric verification codes

Use validationType="alphanumeric" for recovery, backup, or invite codes that mix letters and numbers.

Accept letters and numbers for backup codes such as A7C9XZ.

Grouped layouts

Wrap subsets of inputs in your own layout elements and use <OTPField.Separator> when you want the code presented in smaller visual chunks such as 123-456.

Placeholder hints

<OTPField.Input> is a real input, so native placeholder props and CSS work as usual. This example keeps placeholder hints visible until the active slot receives focus.

Placeholder hints can stay visible until the active slot is focused.

Custom normalization

Use normalizeValue to normalize accepted values before state updates, such as converting alphanumeric codes to uppercase. It runs after validationType filtering, and the result is filtered against validationType again. Use validationType="none" when the normalizer should provide the full validation rule.

Pair custom rules with inputmode for keyboard hints and onValueInvalid for rejected characters.

Letters and digits only. Letters are converted to uppercase.

Masked entry

Use mask when the code should be obscured while it is being typed.

Use mask to obscure the code on shared screens.

API reference

Root

Groups all OTP field parts and manages their state. Renders a <div> element and a visually hidden validation input.

id string | null โ€”
Name
Description

The id of the first input element. Later slots use {id}-2, {id}-3, and so on.

Type
string | null
autocomplete FullAutoFill | null 'one-time-code'
Description

The input autocomplete attribute. Applied to the first slot and hidden validation input.

Type
FullAutoFill | null
Default
'one-time-code'
form string | null โ€”
Name
Description

Identifies the form that owns the hidden input and the slots. The value must match a form element's id in the same document.

Type
string | null
length* number โ€”
Name
Description

The number of OTP input slots. Required so the root can clamp values, detect completion, and render validation markup before every slot has mounted.

Type
number
autoSubmit boolean false
Description

Whether to submit the owning form when the OTP becomes complete.

Type
boolean
Default
false
mask boolean false
Name
Description

Whether the slot inputs should mask entered characters. Pass type on an individual input to override that slot.

Type
boolean
Default
false
inputmode "text" | "none" | "search" | "email" | "tel" | "url" | "numeric" | "decimal" | null โ€”
Description

Virtual keyboard hint for the slots and the hidden validation input.

Type
"text" | "none" | "search" | "email" | "tel" | "url" | "numeric" | "decimal" | null
validationType OTPFieldValidationType 'numeric'
Description

Which characters the OTP accepts.

Type
OTPFieldValidationType
Default
'numeric'
normalizeValue function โ€”
Description

Normalizes the OTP value after whitespace and validationType filtering. The result is filtered again, then clamped to length. It should be idempotent.

Type
(value: string) => string
required boolean | null false
Description

Whether the user must enter a value before submitting a form.

Type
boolean | null
Default
false
disabled boolean | null false
Description

Whether the component should ignore user interaction.

Type
boolean | null
Default
false
readonly boolean | null false
Description

Whether the user should be unable to change the field value.

Type
boolean | null
Default
false
name string | null โ€”
Name
Description

Identifies the field when a form is submitted.

Type
string | null
value string โ€”
Name
Description

The OTP value. Use bind:value to share it with the parent.

Type
string
Binding
bind:value
defaultValue string ''
Description

The value an empty value starts from, as on an HTML input.

Type
string
Default
''
onValueChange function โ€”
Description

Called when the OTP value changes. eventDetails.cancel() vetoes the change. eventDetails.reason is input-change, input-clear, input-paste, or keyboard.

Type
(value: string, eventDetails: OTPFieldChangeEventDetails) => void
onValueInvalid function โ€”
Description

Called when typed or pasted text contains characters rejected before the value updates. value is the attempted string before normalization.

Type
(value: string, eventDetails: OTPFieldInvalidEventDetails) => void
onValueComplete function โ€”
Description

Called when the OTP becomes complete, or when a complete value is pasted over a complete OTP. When the value changes, it runs after that change is stored. autoSubmit submits just after.

Type
(value: string, eventDetails: OTPFieldCompleteEventDetails) => void
render Snippet<[props: HTMLAttributes<HTMLDivElement>, state: OTPFieldRootState, children: Snippet | undefined]> โ€”
Name
Description

Replace the default <div>. Spread props onto the host and render children inside it.

Type
Snippet<[props: HTMLAttributes<HTMLDivElement>, state: OTPFieldRootState, children: Snippet | undefined]>
complete boolean
Name
complete
Description

Whether all slots are filled.

Type
boolean
disabled boolean
Name
disabled
Description

Whether the component should ignore user interaction.

Type
boolean
length number
Name
length
Description

The number of OTP input slots.

Type
number
readOnly boolean
Name
readOnly
Description

Whether the user should be unable to change the field value.

Type
boolean
required boolean
Name
required
Description

Whether the user must enter a value before submitting a form.

Type
boolean
value string
Name
value
Description

The OTP value.

Type
string
touched boolean
Name
touched
Description

Whether the field has been touched.

Type
boolean
dirty boolean
Name
dirty
Description

Whether the field value has changed from its initial value.

Type
boolean
valid boolean | null
Name
valid
Description

Whether the field is valid. null means validity is not known yet.

Type
boolean | null
filled boolean
Name
filled
Description

Whether the field has a value.

Type
boolean
focused boolean
Name
focused
Description

Whether the field is focused.

Type
boolean
data-disabled
Present when the OTP field is disabled.
data-readonly
Present when the OTP field is readonly.
data-required
Present when the OTP field is required.
data-valid
Present when the OTP field is in a valid state (when wrapped in Field.Root).
data-invalid
Present when the OTP field is in an invalid state (when wrapped in Field.Root).
data-dirty
Present when the OTP field's value has changed (when wrapped in Field.Root).
data-touched
Present when the OTP field has been touched (when wrapped in Field.Root).
data-complete
Present when all slots are filled.
data-filled
Present when the OTP field contains at least one character.
data-focused
Present when one of the OTP field inputs is focused.

Input

An individual OTP character input. Renders an <input> element.

render Snippet<[props: HTMLInputAttributes, state: OTPFieldInputState, children: Snippet | undefined]> โ€”
Name
Description

Replace the default <input>. Spread props onto the host.

Type
Snippet<[props: HTMLInputAttributes, state: OTPFieldInputState, children: Snippet | undefined]>
filled boolean
Name
filled
Description

Whether this input contains a character.

Type
boolean
index number
Name
index
Description

The input index.

Type
number
value string
Name
value
Description

The character rendered in this slot.

Type
string
disabled boolean
Name
disabled
Description

Whether the component should ignore user interaction.

Type
boolean
required boolean
Name
required
Description

Whether the user must enter a value before submitting a form.

Type
boolean
readOnly boolean
Name
readOnly
Description

Whether the user should be unable to change the field value.

Type
boolean
touched boolean
Name
touched
Description

Whether the field has been touched.

Type
boolean
dirty boolean
Name
dirty
Description

Whether the field value has changed from its initial value.

Type
boolean
valid boolean | null
Name
valid
Description

Whether the field is valid. null means validity is not known yet.

Type
boolean | null
focused boolean
Name
focused
Description

Whether the field is focused.

Type
boolean
complete boolean
Name
complete
Description

Whether all slots are filled.

Type
boolean
length number
Name
length
Description

The number of OTP input slots.

Type
number
data-disabled
Present when the OTP field is disabled.
data-readonly
Present when the OTP field is readonly.
data-required
Present when the OTP field is required.
data-valid
Present when the OTP field is in a valid state (when wrapped in Field.Root).
data-invalid
Present when the OTP field is in an invalid state (when wrapped in Field.Root).
data-dirty
Present when the OTP field's value has changed (when wrapped in Field.Root).
data-touched
Present when the OTP field has been touched (when wrapped in Field.Root).
data-complete
Present when all slots are filled.
data-filled
Present when the input contains a character.
data-focused
Present when any OTP field input is focused.

Separator

A separator element accessible to screen readers. Renders a <div>.

orientation "horizontal" | "vertical" 'horizontal'
Description

The orientation of the separator.

Type
"horizontal" | "vertical"
Default
'horizontal'
render Snippet<[props: HTMLAttributes<HTMLDivElement>, state: SeparatorState, children: Snippet | undefined]> โ€”
Name
Description

Replace the default <div>. Spread props onto the host element.

Type
Snippet<[props: HTMLAttributes<HTMLDivElement>, state: SeparatorState, children: Snippet | undefined]>
orientation 'horizontal' | 'vertical'
Name
orientation
Description

The orientation of the separator.

Type
'horizontal' | 'vertical'
data-orientation
Indicates the orientation of the separator.