OTP input

Collect a fixed-length numeric one-time code in separate digit cells.

Examples

Properties

PropertyAttributeDescriptionType nameTypeDefault
lengthlengthNumber of digit cells (clamped 4–12, default 6).numbernumber6
valuevalueCombined digit string (no separators).stringstring""
invalidinvalidInvalid state (border + focus ring).booleanbooleanfalse
disableddisabledDisables all cells.booleanbooleanfalse
namenameForm name when using form-associated submission.stringstring—
ariaLabelaria-labelAccessible name for the digit group.stringstring""
ariaLabelledbyaria-labelledbyOptional id reference for the group label.stringstring""
ariaDescribedbyaria-describedbyOptional hint or error ids.stringstring""
langlangLocale for cell accessible names; inherited when omitted. ## Events (host, bubbles + composed) - `input` — value changed from user interaction (typing, paste, backspace across cells). - `change` — user edited the value, then focus left the digit group (same rough contract as native `change`). - `complete` — `CustomEvent` fired once when the combined value **becomes** full (`value.length === length`). `detail.value` is the string.stringstring—

Usage

OTP input collects SMS, email, or backup codes as separate digit cells, styled like duo-field controls. Use inside duo-field with a visible label linked via aria-labelledby when possible.

Do

  • Set invalid and disabled on duo-field only—they mirror onto this control when it is a direct slotted child.
  • Listen for complete when value first reaches full length (detail.value is the code string).
  • Rely on arrow keys and paste for efficient entry; each cell exposes position in its aria-label, localized from @duo/locales using lang.

Don’t

  • Don’t use for non-numeric or variable-length secrets—use a single text field instead.

Events

The host fires input and change (bubbles, composed) like native form controls, and complete when all digits are filled.