OTP Inputs

OTP inputs collect one-time passwords — the short verification codes used in two-factor authentication and passwordless login flows. Each digit gets its own character box, but a single <input> backs them all, so the value submits like any other form field and no JavaScript is required.

The input renders with inputmode="numeric" (mobile numeric keypad), autocomplete="one-time-code" (auto-fill from SMS), and a maxlength and pattern matching the digit count.

Basic OTP

By default, the component renders four character boxes. Click anywhere on the boxes to focus the input and start typing.

Preview
Code
= daisy_otp(name: "verification_code")

6-Digit OTP

Pass length: to change the digit count. DaisyUI lays out up to 8 boxes.

Preview
Code
= daisy_otp(name: "verification_code_6", length: 6)

Joined OTP

The otp-joined modifier connects the character boxes with no gap.

Preview
Code
= daisy_otp(name: "pin", css: "otp-joined")

OTP Sizes

Size modifiers scale the boxes from otp-xs to otp-xl.

Preview
otp-xs
otp-sm
otp-md
otp-lg
otp-xl
Code
- %w[otp-xs otp-sm otp-md otp-lg otp-xl].each do |size|
  .flex.items-center.gap-4
    = daisy_otp(name: "code_#{size.parameterize.underscore}", css: size)
    %span.font-mono.text-sm= size

OTP Colors

Color modifiers tint each box's border and caret; focusing a row adds a matching outline. All of the standard DaisyUI colors are available: otp-neutral, otp-primary, otp-secondary, otp-accent, otp-info, otp-success, otp-warning, and otp-error.

Preview
otp-primary otp-accent otp-error
Code
%div{ class: "grid grid-cols-[auto_auto] items-center gap-4" }
  - %w[otp-primary otp-accent otp-error].each do |color|
    = daisy_otp(name: "code_#{color.parameterize.underscore}", css: color)
    %span.font-mono.text-sm= color

OTP in a Form

Combine the OTP with a fieldset and a submit button for a realistic verification flow. required: true participates in normal HTML form validation.

Since the value is a plain input, your JavaScript can read it like any other field — type a code and click Verify to see for yourself.

Preview
Enter Verification Code
Code
:ruby
  verify_js = <<~JS.squish
    const value = document.querySelector("input[name='otp_code']").value;
    if (value.length < 6) {
      alert(`Hold on — that's only ${value.length} of 6 digits!`);
    } else {
      const sum = value.split("").reduce((total, digit) => total + Number(digit), 0);
      alert(`${value.split("").join(" + ")} = ${sum} — verified! 🎉`);
    }
  JS

= daisy_fieldset do |fieldset|
  - fieldset.with_legend { "Enter Verification Code" }

  = daisy_otp(name: "otp_code", length: 6, required: true)

  = daisy_button(title: "Verify", css: "btn-primary mt-4", html: { onclick: verify_js })
Made with by Profoundry .
Copyright © 2023-2026 Profoundry LLC.
All rights reserved.