OtpInput

Use OtpInput when a person enters a short numeric verification code, such as a two-factor challenge. Each digit has its own box; the complete value is available through onChange and, when name is set, through one hidden form input.

Examples

Six-digit verification code

Typing advances to the next box. Pasting a whole code distributes its digits, including when the paste contains spaces or dashes.

Verification code
Enter the six-digit code.

Invalid or expired code

error replaces hint, marks the digits invalid, and gives the group a linked message.

Verification code
That code has expired. Request a new one.

Accessibility

  • The visible label names the group; every digit announces its position. Set digitLabel to translate the word “Digit”.
  • The first field has autocomplete="one-time-code"; all fields use numeric input mode. The entire autofilled code can be entered into the first field and is split across the boxes.
  • Left and right arrows move between digits. Home and End jump to the first and last digit. Backspace deletes the current digit or moves back when empty. Tab follows the normal input order.
  • error is attached via aria-describedby and marks each digit with aria-invalid.

API and code

Blade: The released Blade v0.10.0 API snapshot has no component for this catalog entry.

NameTypeRequiredDescription
labelstringRequiredVisible and accessible label for the whole code.
lengthnumber—Number of digits. Default: 6.
valuestring—Controlled code, containing only digits.
defaultValuestring—Initial code in uncontrolled mode.
onChange(value: string) => void—Called with the complete current code after each edit.
namestring—Name of a hidden input that submits the combined code.
hintstring—Hint shown below the group, replaced by error.
errorstring—Visible error, connected to the group and every digit.
disabledboolean—Disables all digit inputs.
classNamestring—Additional class on the group.
idstring—Optional stable id for the group.
digitLabelstring—Localized word used in each digit's accessible name. Default: "Digit".

x-data="lyraOtpInput({ … })"

OptionTypeRequiredDescription
lengthnumber—Number of numeric digits. Default: 6.
defaultValuestring—Initial code.
invalidboolean—Adds an invalid state; serve an error message and aria-describedby in the markup.
digitLabelstring—Localized word for each digit's accessible name. Default: "Digit".
html
<div class="lyra-field" x-data="lyraOtpInput({ length: 6 })" x-modelable="code">
  <span id="code-label" class="lyra-label">Verification code</span>
  <div class="lyra-otp" role="group" aria-labelledby="code-label">
    <template x-for="index in positions" :key="index">
      <input
        class="lyra-input lyra-otp__digit"
        type="text"
        :data-index="index"
        inputmode="numeric"
        pattern="[0-9]*"
        :autocomplete="index === 0 ? 'one-time-code' : 'off'"
        x-bind="digit"
      />
    </template>
  </div>
  <input type="hidden" name="code" x-bind:value="code" />
</div>

Serve the label and optional error text with the HTML. Set invalid: true, aria-describedby on the role="group", and a visible error with that id when validation fails. Listen for lyra:change from the component root or bind code with x-model.