OTP Input
One-time password code entry with individual fields, separator, states, underline/rounded variants, and resend timer.
Basic OTP Input
Preview
<div class="otp">
<input class="otp-field otp-field-filled" type="text" maxlength="1" value="4" />
<input class="otp-field otp-field-filled" type="text" maxlength="1" value="2" />
<input class="otp-field" type="text" maxlength="1" value="" />
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
</div> Requires: ux.min.css
<div class="inline-flex gap-2">
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-primary bg-base-200 rounded-field outline-none caret-primary" type="text" maxlength="1" value="4" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-primary bg-base-200 rounded-field outline-none caret-primary" type="text" maxlength="1" value="2" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
<!-- 3 more fields... -->
</div> Requires: tw.min.css
// Auto-advance on input:
// fields.forEach((field, i) => {
// field.addEventListener('input', () => {
// if (field.value && i < fields.length - 1) fields[i + 1].focus();
// });
// field.addEventListener('keydown', (e) => {
// if (e.key === 'Backspace' && !field.value && i > 0) fields[i - 1].focus();
// });
// }); With Separator
Preview
—
<div class="otp">
<input class="otp-field" type="text" maxlength="1" value="1" />
<input class="otp-field" type="text" maxlength="1" value="2" />
<input class="otp-field" type="text" maxlength="1" value="3" />
<span class="otp-separator">—</span>
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
</div> Requires: ux.min.css
<div class="inline-flex gap-2">
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" value="1" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" value="2" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" value="3" />
<span class="flex items-center justify-center w-4 text-xl font-semibold text-base-content/40">—</span>
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
</div> Requires: tw.min.css
// No JavaScript required for static display States
Preview
<!-- Success -->
<div class="otp otp-success mb-4">
<input class="otp-field otp-field-filled" type="text" maxlength="1" value="1" />
<input class="otp-field otp-field-filled" type="text" maxlength="1" value="2" />
<input class="otp-field otp-field-filled" type="text" maxlength="1" value="3" />
<input class="otp-field otp-field-filled" type="text" maxlength="1" value="4" />
</div>
<!-- Error (shakes) -->
<div class="otp otp-error mb-4">
<input class="otp-field" type="text" maxlength="1" value="9" />
<input class="otp-field" type="text" maxlength="1" value="9" />
<input class="otp-field" type="text" maxlength="1" value="9" />
<input class="otp-field" type="text" maxlength="1" value="9" />
</div>
<!-- Disabled -->
<div class="otp otp-disabled">
<input class="otp-field" type="text" maxlength="1" disabled />
<input class="otp-field" type="text" maxlength="1" disabled />
<input class="otp-field" type="text" maxlength="1" disabled />
<input class="otp-field" type="text" maxlength="1" disabled />
</div> Requires: ux.min.css
<!-- Success -->
<div class="inline-flex gap-2 mb-4">
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-success bg-base-200 rounded-field outline-none caret-primary" type="text" maxlength="1" value="1" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-success bg-base-200 rounded-field outline-none caret-primary" type="text" maxlength="1" value="2" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-success bg-base-200 rounded-field outline-none caret-primary" type="text" maxlength="1" value="3" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-success bg-base-200 rounded-field outline-none caret-primary" type="text" maxlength="1" value="4" />
</div>
<!-- Error -->
<div class="inline-flex gap-2 mb-4">
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-error bg-base-100 rounded-field outline-none" type="text" maxlength="1" value="9" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-error bg-base-100 rounded-field outline-none" type="text" maxlength="1" value="9" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-error bg-base-100 rounded-field outline-none" type="text" maxlength="1" value="9" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-error bg-base-100 rounded-field outline-none" type="text" maxlength="1" value="9" />
</div>
<!-- Disabled -->
<div class="inline-flex gap-2 opacity-60">
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-200 rounded-field outline-none cursor-not-allowed text-base-content/40" type="text" maxlength="1" disabled />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-200 rounded-field outline-none cursor-not-allowed text-base-content/40" type="text" maxlength="1" disabled />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-200 rounded-field outline-none cursor-not-allowed text-base-content/40" type="text" maxlength="1" disabled />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-200 rounded-field outline-none cursor-not-allowed text-base-content/40" type="text" maxlength="1" disabled />
</div> Requires: tw.min.css
// Shake animation plays automatically on .otp-error Variants & Sizes
Preview
<!-- Underline variant -->
<div class="otp otp-underline mb-4">
<input class="otp-field" type="text" maxlength="1" value="A" />
<input class="otp-field" type="text" maxlength="1" value="B" />
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
</div>
<!-- Rounded variant -->
<div class="otp otp-rounded mb-4">
<input class="otp-field otp-field-filled" type="text" maxlength="1" value="1" />
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
</div>
<!-- Small -->
<div class="otp otp-sm mb-4">
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
</div>
<!-- Large -->
<div class="otp otp-lg">
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
</div> Requires: ux.min.css
<!-- Underline variant -->
<div class="inline-flex gap-2 mb-4">
<input class="w-12 h-14 text-center text-2xl font-semibold border-0 border-b-2 border-primary bg-transparent rounded-none outline-none caret-primary" type="text" maxlength="1" value="A" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-0 border-b-2 border-primary bg-transparent rounded-none outline-none caret-primary" type="text" maxlength="1" value="B" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-0 border-b-2 border-base-300 bg-transparent rounded-none outline-none focus:border-primary caret-primary" type="text" maxlength="1" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-0 border-b-2 border-base-300 bg-transparent rounded-none outline-none focus:border-primary caret-primary" type="text" maxlength="1" />
</div>
<!-- Rounded variant -->
<div class="inline-flex gap-2 mb-4">
<input class="w-14 h-14 text-center text-2xl font-semibold border-[1.5px] border-primary bg-base-200 rounded-full outline-none caret-primary" type="text" maxlength="1" value="1" />
<input class="w-14 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-full outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
<input class="w-14 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-full outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
<input class="w-14 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-full outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
</div>
<!-- Small -->
<div class="inline-flex gap-2 mb-4">
<input class="w-10 h-12 text-center text-xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
<input class="w-10 h-12 text-center text-xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
<input class="w-10 h-12 text-center text-xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
<input class="w-10 h-12 text-center text-xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
</div>
<!-- Large -->
<div class="inline-flex gap-2">
<input class="w-14 h-16 text-center text-3xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
<input class="w-14 h-16 text-center text-3xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
<input class="w-14 h-16 text-center text-3xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
<input class="w-14 h-16 text-center text-3xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
</div> Requires: tw.min.css
// No JavaScript required for variants With Helper & Resend
Preview
Enter the 6-digit code sent to your phone
Didn't receive the code?
<div class="otp-wrapper">
<div class="otp">
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
<input class="otp-field" type="text" maxlength="1" />
</div>
<div class="otp-helper">Enter the 6-digit code sent to your phone</div>
<div class="otp-resend">
Didn't receive the code?
<button class="otp-resend-btn" disabled>Resend in 45s</button>
</div>
</div> Requires: ux.min.css
<div class="inline-flex flex-col gap-2">
<div class="inline-flex gap-2">
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
<input class="w-12 h-14 text-center text-2xl font-semibold border-[1.5px] border-base-300 bg-base-100 rounded-field outline-none focus:border-primary focus:ring-3 focus:ring-primary/15 caret-primary" type="text" maxlength="1" />
</div>
<div class="text-center text-[0.8125rem] text-base-content/60">Enter the 6-digit code sent to your phone</div>
<div class="flex items-center justify-center gap-1 text-[0.8125rem] text-base-content/60">
Didn't receive the code?
<button class="bg-transparent border-none p-0 text-base-content/40 cursor-not-allowed" disabled>Resend in 45s</button>
</div>
</div> Requires: tw.min.css
// Countdown timer:
// let seconds = 60;
// const timer = setInterval(() => {
// seconds--;
// btn.textContent = 'Resend in ' + seconds + 's';
// if (seconds <= 0) { clearInterval(timer); btn.disabled = false; btn.textContent = 'Resend'; }
// }, 1000); | Class | Description |
|---|---|
.otp | Container (inline-flex) |
.otp-field | Individual input (48x56px) |
.otp-field-filled | Filled field (tinted bg) |
.otp-separator | Dash between groups |
.otp-sm | Small (40x48px) |
.otp-lg | Large (56x64px) |
.otp-success | Success state (green) |
.otp-error | Error state (red + shake) |
.otp-disabled | Disabled state |
.otp-loading | Loading state |
.otp-underline | Underline variant |
.otp-rounded | Circular fields |
.otp-secure | Masked (dots) input |
.otp-wrapper | Wrapper with helper text |
.otp-helper | Helper text |
.otp-helper-error | Error helper text |
.otp-helper-success | Success helper text |
.otp-resend | Resend timer area |
.otp-resend-btn | Resend button |
.otp.glass | Glass morphism variant |