Input OTP

Accessible one-time-password input with keyboard navigation and paste support.

Usage

Example

Composition

InputOtpGroup and InputOtpSeparator compose freely — split slots into however many groups make sense, with a separator between each.

Example

Pattern

Pass pattern: with a single-character regex class to define what InputOtp accepts. The default is "[0-9]" (digits only).

Alphanumeric

Four digits

A common pattern for PIN codes — just pass a shorter length.

Example

Disabled

Example

Invalid

Pass aria_invalid: "true" to each InputOtpSlot to show an error state.

Example

Form

A full example combining InputOtp with Card, Button, and InlineLink — bigger slots via class:, a resend action, and fallback links.

Verify your login

Reacting to completion

The controller dispatches a ruby-ui--input-otp:complete custom event (detail: { value }) once the value reaches length characters, and a ruby-ui--input-otp:input event on every change. Wire a Stimulus action on a parent element to react — for example, to auto-submit a form:

// app/javascript/controllers/otp_form_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  submit() {
    this.element.requestSubmit()
  }
}
<form data-controller="otp-form" data-action="ruby-ui--input-otp:complete->otp-form#submit">
	<!-- InputOtp(...) here -->
</form>

Installation

Components

ComponentBuilt usingSource
InputOtpPhlex
InputOtpDocsPhlex
InputOtpGroupPhlex
InputOtpSeparatorPhlex
InputOtpSlotPhlex
InputOtpControllerStimulus JS