Skip to content

components otp

GitHub Actions edited this page Sep 18, 2026 · 2 revisions

components/otp

Import: import { Otp } from "@tundralibs/ui/otp"

Rendered in every variant on the catalogue (deno task build:demos, then demo/index.html). Guides: Getting started · rAPId integration · Theming.

Functions

Otp

Otp(props: OtpProps): Html

One-time code entry. Progressive: without JS a single autocomplete="one-time-code" input is what the user sees and submits; with JS (otp.js) it becomes the hidden value carrier behind N cells that auto-advance, accept a pasted/autofilled code across all cells, and walk back on Backspace. The form always submits exactly one field, name, whichever way it was entered.

Types

OtpProps

Prop Type Required Description
id string yes Required: cells are <id>-1 … <id>-N, the label targets the first.
name string yes The submitted field — ONE value, the joined code.
length number Number of cells. Default 6.
value string Prefilled code (e.g. re-rendered after a failed attempt).
label `string Html`
hint `string Html`
error string Set from RapidFormError.fields[name] (§6).
mode `"numeric" "alphanumeric"`
groups number Visual separator after every groups cells, e.g. 3 → 123 · 456.
autofocus boolean
disabled boolean
autoSubmit boolean Submit the surrounding form as soon as every cell is filled.
attrs Attrs

Usage

Each example as the rAPId call and the HTML it renders — the markup a plain page writes by hand. Icons are inline SVG in the real output; they are shortened to <svg …>…</svg> here.

A six-digit SMS code

One autocomplete="one-time-code" input submits under name; the cells are an enhancement. autoSubmit submits the form when the last cell fills.

Otp({ id: "sms-code", name: "code", label: "Enter the code we texted you", groups: 3, autoSubmit: true })
<div class="otp" data-otp data-otp-mode="numeric" data-otp-submit="">
  <label class="form-field__label" for="sms-code-value">Enter the code we texted you</label>
  <input class="otp__value" id="sms-code-value" name="code" type="text" value="" maxlength="6" autocomplete="one-time-code" autocapitalize="off" spellcheck="false" inputmode="numeric" pattern="[0-9]{6}">
  <div class="otp__cells" role="group" aria-label="Enter the code we texted you">
    <input class="otp__cell" id="sms-code-1" type="text" value="" aria-label="Digit 1 of 6" autocapitalize="off" autocorrect="off" spellcheck="false" tabindex="-1" inputmode="numeric" pattern="[0-9]*" autocomplete="one-time-code">
    <input class="otp__cell" id="sms-code-2" type="text" value="" aria-label="Digit 2 of 6" autocapitalize="off" autocorrect="off" spellcheck="false" tabindex="-1" inputmode="numeric" pattern="[0-9]*" autocomplete="off">
    <input class="otp__cell" id="sms-code-3" type="text" value="" aria-label="Digit 3 of 6" autocapitalize="off" autocorrect="off" spellcheck="false" tabindex="-1" inputmode="numeric" pattern="[0-9]*" autocomplete="off">
    <span class="otp__sep" aria-hidden="true"></span>
    <input class="otp__cell" id="sms-code-4" type="text" value="" aria-label="Digit 4 of 6" autocapitalize="off" autocorrect="off" spellcheck="false" tabindex="-1" inputmode="numeric" pattern="[0-9]*" autocomplete="off">
    <input class="otp__cell" id="sms-code-5" type="text" value="" aria-label="Digit 5 of 6" autocapitalize="off" autocorrect="off" spellcheck="false" tabindex="-1" inputmode="numeric" pattern="[0-9]*" autocomplete="off">
    <input class="otp__cell" id="sms-code-6" type="text" value="" aria-label="Digit 6 of 6" autocapitalize="off" autocorrect="off" spellcheck="false" tabindex="-1" inputmode="numeric" pattern="[0-9]*" autocomplete="off">
  </div>
</div>

CSS hooks

Classes defined by components/otp/otp.css — structural, token-driven; override from an unlayered stylesheet (see Theming):

.js, .otp, .otp--invalid, .otp__cell, .otp__cells, .otp__sep, .otp__value

Behaviour

components/otp/otp.js ships in ui.js (delegated on document, re-initialised after a rAPId swap).

Attributes it reads or writes: data-filled, data-otp, data-otp-completed, data-otp-mode, data-otp-submit.

Events: otp:complete, rapid:swapped.

Clone this wiki locally