Input OTP primitive
Headless Input OTP: the behavior, keyboard support and ARIA of its pattern, with no styles.
@ndop/primitives/input-otp
Import
Primitives ship in the @ndop/primitives package and have no styles. Their state is on data attributes for you to style. The styled Input OTP is built on this one.
import {
NdInputOtp,
NdInputOtpGroup,
NdInputOtpSeparator,
NdInputOtpInput,
NdInputOtpSlot,
} from '@ndop/primitives/input-otp';Accessibility
Keyboard
Keys the component handles.
| Key | Action |
|---|---|
| Backspace | Deletes the last character. |
Focus
- Clicking any slot focuses the input, with the caret at the end of the code.
- Focus stays on the input as the code fills; the
completedoutput lets the app move on. - Leaving the input marks a bound field touched.
Right-to-left
The root has dir="ltr": a code's characters read left to right in every language, as phone numbers do, so the slots don't mirror.
API reference
NdInputOtp
[ndInputOtp]from @ndop/primitives/input-otpHeadless one-time code input: one native input[ndInputOtpInput] holds
the code, so screen readers, autofill and password managers see a single
field, and [ndInputOtpSlot]s draw its characters. Characters allow
rejects are dropped, and pasting fills the code from the start. The root
owns the value, so it's the ControlValueAccessor that Signal Forms
([formField]), reactive and template-driven forms bind (ADR-0004,
amendments 1 and 4).
| NdInputOtp binding | Type | Default |
|---|---|---|
[defaultValue]Initial value when it isn't bound. | string | '' |
[length]requiredThe code's length: how many slots it fills. | number | — |
[allow]A regular expression one character must match to be kept, or its
source. Digits by default. | RegExp | /\d/ |
[inputMode]The input's inputmode, which picks the on-screen keyboard. | 'numeric' | 'text' | 'numeric' |
[disabled]Disables the input. A disabled bound field does too. | boolean | false |
[invalid]Marks the code invalid when no forms library is bound; with one, the
field's state decides. | boolean | false |
[(value)]The code. Two-way bindable with [(value)]. | string | '' |
(completed)Emits the code when the user completes it. | string | — |
| Data attribute | Values |
|---|---|
data-complete | — |
data-disabled | — |
data-invalid | — |
NdInputOtpGroup
[ndInputOtpGroup]from @ndop/primitives/input-otpA group of NdInputOtpSlots, hidden from assistive technology:
the input is what it reads.
Manages aria-hidden.
NdInputOtpSeparator
[ndInputOtpSeparator]role separatorfrom @ndop/primitives/input-otpA visual separator between groups of slots, hidden from assistive technology.
Manages aria-hidden.
NdInputOtpInput
input[ndInputOtpInput]role nativefrom @ndop/primitives/input-otpThe native input of a NdInputOtp, which holds the whole code. Name
it with a label or aria-label; style it to sit, invisible, over the
slots, so clicking a slot focuses it.
Manages aria-invalid.
| NdInputOtpInput binding | Type | Default |
|---|---|---|
[id]Element id; also the key a label[ndLabel] uses to find it. | string | undefined | — |
| Data attribute | Values |
|---|---|
data-invalid | — |
NdInputOtpSlot
[ndInputOtpSlot]from @ndop/primitives/input-otpOne character of a NdInputOtp's code. Its text is that character;
data-active marks where the next one goes, and data-caret an active
empty slot, to draw a caret in.
Manages aria-hidden.
| NdInputOtpSlot binding | Type | Default |
|---|---|---|
[index]requiredThe character's position in the code, from 0. | number | — |
| Data attribute | Values |
|---|---|
data-active | — |
data-filled | — |
data-caret | — |
data-invalid | — |