Skip to content

Components · OtpInput

OtpInput

Six visible slots over one real input. Type, paste the whole code, or navigate with the arrow keys — screen readers hear a single labelled field, not six unlabelled boxes.

import { Field, OtpInput } from "@luc/ui";

Examples

Basic

`autocomplete="one-time-code"` is set for you, and the pattern decides which characters the field accepts.

Six digits, sent to research@acme.dev.

value: —

Characters, grouping and sizes

1
2
3
4

States

Empty, rejected and locked: the invalid state is a message on the field, and a disabled code keeps its digits readable.

Empty

1
2
3
4

Invalid

field-level error

1
2
3
4

Disabled

Usage

import { OtpInput } from "@luc/ui";
<OtpInput length={6} groups={[3, 3]} value={code} onValueChange={setCode} aria-label="Verification code" />

`length` fixes the number of slots; `onComplete` fires once the last one is filled, which is where the check belongs.

API

Read from the published TypeScript API, so a prop that is not listed here does not exist and a default that is listed is the one the compiler sees.

Exported symbols
ExportKindSignature
OtpInput14 documented props({ length, value, defaultValue, onValueChange, onComplete, mode, size, invalid, disabled, groups, className, id, name, ...props }: OtpInputProps) => import("@types/react").JSX.Element

OtpInput props

Type: OtpInputProps

Values the compiler reads from the declaration.

OtpInput props
PropTypeDefaultNotes
aria-label?string | undefined—Accessible name. A code field is usually labelled by its `<Field>`.
className?string | undefined—
defaultValue?string | undefined—
disabled?boolean | undefined—
groups?number[] | undefined—Groups the slots visually, e.g. `3` renders 3+3 for a six-digit code.
id?string | undefined—
invalid?boolean | undefined—
length?number | undefined—Number of characters.
mode?OtpMode | undefined—
name?string | undefined—
onComplete?((value: string) => void) | undefined—Fired when every slot is filled.
onValueChange?((value: string) => void) | undefined—
size?ControlSize | undefined—
value?string | undefined—

Guidelines

Do

  • Give it `length` and, when the provider breaks the code up, `groups` — six digits read better as three and three.
  • Run the check from `onComplete` rather than watching the value, so it fires once instead of on every keystroke.
  • Set `mode` only when the code really is alphanumeric; the default keeps a numeric keypad on a phone.

Don't

  • Ask for more characters than the provider issues: extra empty slots invite a typo and a failed code.
  • Build the slots out of separate inputs — the group is announced as one field, and separate boxes lose that.
  • Put the resend control inside the code field; resending belongs to the page that owns the request.

Accessibility

The slots are one labelled field: assistive technology hears a single input of `length` characters carrying `autocomplete="one-time-code"`, not a row of unlabelled boxes. Typing advances, Backspace retreats, a pasted code fills every slot at once, and `invalid` reaches the input from a `Field` that owns the message.

Luc UI v1.0OtpInputdark theme