Browse Components

OTP

One-time password (OTP) fields for verification codes, with paste and autofill support.

Basic

Type or paste a 6-digit code. Connected digit slots share one native field for selection, keyboard editing and one-time-code autofill when supplied by your device.

Enter the 6-digit code sent to your email.

View Code
HTML
<div class="field">
  <label for="verification-code">
    Verification code
  </label>
  <input
    class="input otp"
    data-otp
    id="verification-code"
    name="code"
    type="text"
    inputmode="numeric"
    autocomplete="one-time-code"
    maxlength="6"
    pattern="[0-9]{6}"
    required
    spellcheck="false"
    autocapitalize="off"
    dir="ltr"
    aria-describedby="verification-help"
  >
  <p class="muted" id="verification-help">
    Enter the 6-digit code sent to your email.
  </p>
</div>

Four digits

Set maxlength and pattern to the same code length. Leading zeroes are preserved.

Enter the 4-digit code sent to your email.

View Code
HTML
<div class="field">
  <label for="short-code">
    Verification code
  </label>
  <input
    class="input otp"
    data-otp
    id="short-code"
    name="code"
    type="text"
    inputmode="numeric"
    autocomplete="one-time-code"
    maxlength="4"
    pattern="[0-9]{4}"
    required
    spellcheck="false"
    autocapitalize="off"
    dir="ltr"
    aria-describedby="short-help"
  >
  <p class="muted" id="short-help">
    Enter the 4-digit code sent to your email.
  </p>
</div>

Letters and digits

Eight-character codes accept letters and digits. The optional behavior converts letters to uppercase and removes separators from pasted codes.

Enter the 8-character code sent to your email.

View Code
HTML
<div class="field">
  <label for="alpha-code">
    Verification code
  </label>
  <input
    class="input otp"
    data-otp
    data-otp-mode="alphanumeric"
    id="alpha-code"
    name="code"
    type="text"
    inputmode="text"
    autocomplete="one-time-code"
    maxlength="8"
    pattern="[A-Za-z0-9]{8}"
    required
    spellcheck="false"
    autocapitalize="characters"
    dir="ltr"
    aria-describedby="alpha-help"
  >
  <p class="muted" id="alpha-help">
    Enter the 8-character code sent to your email.
  </p>
</div>

Verification error

Keep the rejected code editable and show a linked error. Your application verifies the code and clears the error when appropriate.

This code has expired. Request a new code and try again.

View Code
HTML
<div class="field">
  <label for="error-code">
    Verification code
  </label>
  <input
    class="input otp"
    data-otp
    id="error-code"
    name="code"
    type="text"
    inputmode="numeric"
    autocomplete="one-time-code"
    maxlength="6"
    pattern="[0-9]{6}"
    value="123456"
    aria-invalid="true"
    required
    spellcheck="false"
    autocapitalize="off"
    dir="ltr"
    aria-describedby="error-help"
  >
  <p class="field-error" id="error-help">
    This code has expired. Request a new code and try again.
  </p>
</div>

Disabled and read-only

Native disabled fields cannot be edited or submitted. Read-only fields remain selectable and retain their form value.

Enter the 6-digit code sent to your email.

This code is read-only.

View Code
HTML
<div class="stack">
  <div class="field">
    <label for="disabled-code">
      Verification code
    </label>
    <input
      class="input otp"
      data-otp
      id="disabled-code"
      name="code"
      type="text"
      inputmode="numeric"
      autocomplete="one-time-code"
      maxlength="6"
      pattern="[0-9]{6}"
      disabled
      required
      spellcheck="false"
      autocapitalize="off"
      dir="ltr"
      aria-describedby="disabled-help"
    >
    <p class="muted" id="disabled-help">
      Enter the 6-digit code sent to your email.
    </p>
  </div>
  <div class="field">
    <label for="readonly-code">
      Verified code
    </label>
    <input
      class="input otp"
      data-otp
      id="readonly-code"
      name="code"
      type="text"
      inputmode="numeric"
      autocomplete="one-time-code"
      maxlength="6"
      pattern="[0-9]{6}"
      readonly
      value="012345"
      required
      spellcheck="false"
      autocapitalize="off"
      dir="ltr"
      aria-describedby="readonly-help"
    >
    <p class="muted" id="readonly-help">
      This code is read-only.
    </p>
  </div>
</div>

Right to left

Hebrew labels follow the surrounding direction while the code remains left to right.

הזינו את הקוד בן 6 הספרות שנשלח לאימייל שלכם.

View Code
HTML
<div dir="rtl" lang="he">
  <div class="field">
    <label for="he-code-code">
      קוד אימות
    </label>
    <input
      class="input otp"
      data-otp
      id="he-code-code"
      name="code"
      type="text"
      inputmode="numeric"
      autocomplete="one-time-code"
      maxlength="6"
      pattern="[0-9]{6}"
      required
      spellcheck="false"
      autocapitalize="off"
      dir="ltr"
      aria-describedby="he-code-help"
    >
    <p class="muted" id="he-code-help">
      הזינו את הקוד בן 6 הספרות שנשלח לאימייל שלכם.
    </p>
  </div>
</div>

Installation

Download these files into the matching paths in your project, or use Create to assemble a kit. Include each dependency once. Do not also load app.css.

Add to your page
<link rel="stylesheet" href="/library/assets/base.css">
<link rel="stylesheet" href="/library/assets/field.css">
<link rel="stylesheet" href="/library/assets/otp.css">
<script defer src="/library/assets/otp.js"></script>

13,090 bytes CSS including base · 4,581 bytes runtime JavaScript

Usage

One native input

Use type=text to preserve leading zeroes. Match maxlength to the exact-length pattern, keep a visible label and link instructions using aria-describedby. One-time-code autofill depends on the browser and operating system.

Validation and security

The component only collects codes. Your application or backend owns generation, verification, expiry, resend and rate limits. Never log codes. otp:complete signals a complete input, not a verified identity, and never submits automatically.

Optional enhancement

Load otp.js for connected visual digit slots, formatted paste and normalization. The slots are hidden from assistive technology; one native input provides a single tab stop and form value. Without JavaScript the input remains usable. Numeric codes use ASCII digits; alphanumeric mode uses uppercase ASCII letters and digits. Native keyboard selection, Backspace, Delete, disabled, readonly and form reset remain available.

Lifecycle

Call layoutOTP.refresh(root) after mounting and destroy(input) before removal. Dispatch input after programmatic value changes if normalization or completion notification is needed.

Building with AI? The AI Manifest has these notes and the full contract. See the AI Guide.