Input OTP

A one-time passcode input using a single native <input>, wrapped in <span class="otp"> so it can be cropped to look like separate boxes.

Composed of

Text Field
The input styling it builds on

Works with

Field
Label and hint text

One real <input> underneath, not six inputs stitched together with JavaScript. Paste, backspace, and mobile SMS autofill through autocomplete="one-time-code" all work on their own, and a screen reader announces one text field.

The wrapper only clips overflow. The input is rendered one cell wider than the wrapper, so the text cursor always has room and never scrolls the field. The tradeoff is that CSS can't count typed characters, so the focus ring covers the whole input instead of the box being filled.

Standalone

<link rel="stylesheet" href="https://esm.sh/@erikt/ui/input-otp.css" />

Default

Set inputmode="numeric", pattern="\d*", and maxlength to match the number of digits.

<span class="otp">
  <input
    type="text"
    inputmode="numeric"
    pattern="\d*"
    maxlength="4"
    autocomplete="one-time-code"
    aria-label="One-time passcode"
  />
</span>

Length

The number of boxes follows maxlength automatically. Override --otp-length on the wrapper directly if you ever need to.

<span class="otp">
  <input
    type="text"
    inputmode="numeric"
    pattern="\d*"
    maxlength="4"
    autocomplete="one-time-code"
    aria-label="One-time passcode"
  />
</span>

Placeholder

A placeholder of dashes or dots reads naturally as empty boxes, since the same letter spacing applies to it.

<span class="otp">
  <input
    type="text"
    inputmode="numeric"
    pattern="\d*"
    maxlength="6"
    autocomplete="one-time-code"
    placeholder="000000"
    aria-label="One-time passcode"
  />
</span>

In a field

Drop it inside a Field for a visible label and hint text.

<label class="field">
  <span>Enter PIN</span>
  <span class="otp">
    <input
      type="text"
      inputmode="numeric"
      pattern="\d*"
      maxlength="4"
      autocomplete="one-time-code"
    />
  </span>
  <small>We sent a 4-digit code to your phone.</small>
</label>

Disabled

<span class="otp">
  <input type="text" inputmode="numeric" pattern="\d*" maxlength="6" disabled />
</span>

API reference

Type Classes / attributes What it does
Length [maxlength] Sets the number of boxes, from 1 to 10
Box count --otp-length: 6 Overrides the number of boxes
Box size --otp-cell-size: 2.75rem Width and height of each box
Disabled [disabled] Fades the input

Search 5021 icons

Type a name to find icons from the Tabler icon set.

      Move Open Esc Close