Input OTP
One-time code field: N joined single-char inputs with auto-advance, paste distribution and a hidden form mirror.
INSTALL
1pnpm dlx @sayagodev/mo add input-otpOr import the files from the package (no copy):
1import "@sayagodev/mo/css/input-otp.css";2import "@sayagodev/mo/js/input-otp.js";
EXAMPLES
Basic
Enter the 6-digit code sent to your email.
1<mo-otp length="6" name="code"></mo-otp>2<p class="text-light" style="font-size: var(--text-8); margin-block-start: var(--space-2);">Enter the 6-digit code sent to your email.</p>3
Four digits
1<mo-otp length="4" name="four-digits"></mo-otp>2
Separator
Separator between groups — type across both fields.
Single field with visual separator (recommended)
Two linked fields (auto-advances to next)
1<div class="vstack gap-3">2 <div>3 <small class="text-light" style="display:block; margin-block-end: var(--space-2);">Single field with visual separator (recommended)</small>4 <mo-otp length="6" data-separator="3"></mo-otp>5 </div>6 <div>7 <small class="text-light" style="display:block; margin-block-end: var(--space-2);">Two linked fields (auto-advances to next)</small>8 <div class="hstack gap-2">9 <mo-otp length="2"></mo-otp>10 <span aria-hidden="true" style="color: var(--muted-foreground);">—</span>11 <mo-otp length="4"></mo-otp>12 </div>13 </div>14</div>15<small class="text-light">Separator between groups — type across both fields.</small>16
Pattern
1<div class="vstack gap-2">2 <label data-field>3 Digits only (default)4 <mo-otp length="6" data-pattern="numeric"></mo-otp>5 </label>6 <label data-field>7 Alphanumeric8 <mo-otp length="6" data-pattern="alphanumeric"></mo-otp>9 </label>10</div>11
Disabled
1<mo-otp length="6" disabled></mo-otp>2
Invalid
Invalid code — try again.
1<mo-otp length="6" aria-invalid="true" value="12"></mo-otp>2<small class="error" style="display:block; color: var(--destructive); font-size: var(--text-8);">Invalid code — try again.</small>3
USAGE
1<mo-otp length="6" name="code"></mo-otp>2 3<!-- variants -->4<mo-otp length="4"></mo-otp>5<mo-otp length="8" data-pattern="alphanumeric"></mo-otp>
API
NAMEKINDDESCRIPTION
<mo-otp>elementGenerates cells + optional hidden mirror; emits change
lengthattributeCell count (default 4, clamped 1–12)
nameattributeHidden input mirroring the full value
data-patternattributenumeric (default) · alphanumeric
--mo-otp-cell-sizetokenSlot size hook (2.25rem)
FILES
src/css/input-otp.csssrc/js/input-otp.jsInstall:
mo add input-otpTHEMING · PLAYGROUND
This is the exact component from the examples above, wearing a completely different theme. Edit the tokens and --mo-* hooks in the editor — autocomplete knows them all — and the preview obeys in real time. Your CSS always wins.
Global tokens
--muted-foreground--radiusComponent hooks
--mo-otp-cell-sizePreview
Your CSS
Try it: type --mo- for the component hooks, or edit any value — the preview obeys in real time.