InputsReact
A one-time password input made of single-character slots.
Rendered by React 19.3.1
Loading React…Installation
npm i @hamur/reactNot on npm yet. The package goes out under the chosen name.
Anatomy
Import the component and assemble its parts:
<OTPField.Root>
<OTPField.Separator />
<OTPField.Input />
</OTPField.Root>Examples
Alphanumeric
validationType accepts letters and digits for recovery or invite codes.
Grouped
Separator splits the slots into groups, such as 123-456.
Custom Sanitize
normalizeValue uppercases what is typed before it is accepted.
Password
mask hides the characters while they are typed.
API reference
19 props across 3 parts, in React syntax. className, style, render are listed once, under Shared props.
InputOTPField.Input
An individual OTP character input. Renders an <input>.
| Data attribute | Description |
|---|---|
data-complete | Present when all slots are filled. |
data-filled | Present when the input contains a character. |
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-touched | Present when the OTP field has been touched (when wrapped in Field.Root). |
data-dirty | Present when the OTP field's value has changed (when wrapped in Field.Root). |
data-focused | Present when any OTP field input is focused. |
RootOTPField.Root
Groups all OTP field parts and manages their state. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
nameIdentifies the field when a form is submitted. | string | — |
defaultValueThe uncontrolled OTP value when the component is initially rendered. | string | — |
valueThe OTP value. | string | — |
onValueChangeCallback fired when the OTP value changes. | ((value: string, eventDetails: OTPFieldRootChangeEventDetails) => void) | — |
autoCompleteThe input autocomplete attribute. | string | 'one-time-code' |
autoSubmitWhether to submit the owning form when the OTP becomes complete. | boolean | false |
formA string specifying the form element with which the hidden input is associated. | string | — |
inputModeThe virtual keyboard hint applied to the slot inputs and hidden validation input. | "search" | "text" | "none" | "tel" | "url" | "email" | "numeric" | "decimal" | — |
lengthrequiredThe number of OTP input slots. | number | — |
maskWhether the slot inputs should mask entered characters. | boolean | false |
normalizeValueFunction that normalizes the OTP value after whitespace and validationType filtering. | ((value: string) => string) | — |
onValueCompleteCallback function that is fired when the OTP value becomes complete, or when a complete value | ((value: string, eventDetails: OTPFieldRootCompleteEventDetails) => void) | — |
onValueInvalidCallback fired when entered text contains characters that are rejected by validation or | ((value: string, eventDetails: OTPFieldRootInvalidEventDetails) => void) | — |
validationTypeThe type of input validation to apply to the OTP value. | OTPValidationType | 'numeric' |
disabledWhether the component should ignore user interaction. | boolean | false |
readOnlyWhether the user should be unable to change the field value. | boolean | false |
requiredWhether the user must enter a value before submitting a form. | boolean | false |
idThe id of the first input element. | string | — |
| Data attribute | Description |
|---|---|
data-complete | Present when all slots are filled. |
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-touched | Present when the OTP field has been touched (when wrapped in Field.Root). |
data-dirty | Present when the OTP field's value has changed (when wrapped in Field.Root). |
data-filled | Present when the OTP field contains at least one character. |
data-focused | Present when one of the OTP field inputs is focused. |
SeparatorOTPField.Separator
A separator element accessible to screen readers. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
orientationThe orientation of the separator. | Orientation | 'horizontal' |
| Data attribute | Description |
|---|---|
data-orientation | Indicates the orientation of the separator. |
Shared props
Every part that renders an element takes these.
| Prop | Type |
|---|---|
classNameCSS class applied to the element, or a function that
returns a class based on the component's state. | string | ((state: State) => string | undefined) |
styleStyle applied to the element, or a function that
returns a style object based on the component's state. | React.CSSProperties | ((state: State) => React.CSSProperties | undefined) |
renderAllows you to replace the component's HTML element
with a different tag, or compose it with another component. | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, State> |
Keyboard and accessibility
Keyboard
| Keys | Does | Part |
|---|---|---|
| Fills the slot and moves to the next one | Input | |
| ArrowLeftArrowRight | Moves between slots | Input |
| Home | Moves to the first slot | Input |
| End | Moves to the first empty slot at the end | Input |
| Backspace | Deletes the character and moves to the previous slot | Input |
| Delete | Deletes the character and stays in the slot | Input |
Accessibility
| Part | Sets | So that |
|---|---|---|
| Root | role="group", aria-labelledby to the Field label | the slots are read as one named field |
| Input | tabindex="0" on the active slot only | Tab passes the whole code in one step |
| Input | the field's label on the first slot, your aria-label on the others | each slot can be named, such as "Character 2 of 6" |
| Input | aria-invalid when validation fails | the error state is read on every slot |
| Separator | role="separator" | a visual break between groups of slots is announced as such |
Focus order
- The field is one tab stop: the active slot, which is the first empty one.
- Typing and the arrow keys move between slots;
Tableaves the field.