One-time password (OTP) input component with individual digit slots.
Provides a composable OTP input following the shadcn/ui InputOTP anatomy
adapted for Phoenix LiveView. Each digit is rendered as a separate
<input type="text" maxlength="1"> element with automatic focus advancement
on input and focus-back-on-backspace behaviour via inline onkeyup /
onkeydown handlers.
No external JS hook required — navigation is handled with minimal inline event handlers.
Enhancements
type—:numeric(default) or:alphanumeric(pattern[A-Za-z0-9])separator— character shown between the two halves (e.g."-")grouped— visual grouping: removes inner rounded corners and gaps
Sub-components
| Component | Element | Purpose |
|---|---|---|
input_otp/1 | Group + N slots | Simple all-in-one OTP field (most common usage) |
input_otp_group/1 | <div role="group"> | Container that groups slots and separators |
input_otp_slot/1 | <input type="text"> | Individual digit cell |
input_otp_separator/1 | <div aria-hidden> | Visual separator between slot groups |
Simple usage
<%!-- 6-digit numeric OTP --%>
<.input_otp id="otp" name="otp" value={@otp} />
<%!-- 6-digit alphanumeric with separator and grouping --%>
<.input_otp id="code" name="code" value={@code} type={:alphanumeric} separator="-" grouped={true} />
<%!-- 4-digit PIN --%>
<.input_otp id="pin" name="pin" value={@pin} length={4} />
Summary
Functions
Renders a complete OTP input field as a group of individual digit slots.
Renders the OTP group container <div role="group">.
Renders a decorative separator <div> between OTP slot groups.
Renders a single OTP digit <input type="text" maxlength="1"> cell.
Functions
Renders a complete OTP input field as a group of individual digit slots.
Attributes
id(:string) (required) - Base ID for the group and each individual slot. Slot IDs are derived as#{id}-#{index}.length(:integer) - Total number of digit slots to render. Defaults to6.name(:string) - Base name for slots. Each slot name is#{name}[#{index}]. Defaults tonil.value(:string) - Current OTP string. Characters are distributed to slots by position. Defaults to"".disabled(:boolean) - Whentrue, all digit slots are disabled. Defaults tofalse.type(:atom) -:numericusesinputmode=numeric.:alphanumericusesinputmode=textwith pattern. Defaults to:numeric. Must be one of:numeric, or:alphanumeric.separator(:string) - Character shown between the two halves of slots (e.g."-"). Nil = no separator. Defaults tonil.grouped(:boolean) - Whentrue, removes inner rounded corners/gaps to visually group slots per half. Defaults tofalse.class(:string) - Additional CSS classes merged into the group container viacn/1. Defaults tonil.
Renders the OTP group container <div role="group">.
Attributes
id(:string) - ID for the group container element. Defaults tonil.class(:string) - Additional CSS classes. Defaults tonil.- Global attributes are accepted. Additional HTML attributes forwarded to the group
<div>.
Slots
inner_block(required) - Slot content:input_otp_slot/1andinput_otp_separator/1components.
Renders a decorative separator <div> between OTP slot groups.
Attributes
class(:string) - Additional CSS classes. Defaults tonil.
Renders a single OTP digit <input type="text" maxlength="1"> cell.
Attributes
index(:integer) (required) - Zero-based slot position.name(:string) - Thenameattribute of the<input>. Defaults tonil.value(:string) - The current digit value. Defaults to"".id(:string) - ID for the<input>element. Defaults tonil.next_id(:string) - ID of the next slot for auto-advance. Defaults tonil.prev_id(:string) - ID of the previous slot for backspace-back. Defaults tonil.disabled(:boolean) - Whentrue, disables the input. Defaults tofalse.input_type(:atom) - Input mode —:numericor:alphanumeric. Defaults to:numeric. Must be one of:numeric, or:alphanumeric.group_pos(:atom) - Grouped position —:first,:middle,:last,:standalone, ornil. Defaults tonil.class(:string) - Additional CSS classes. Defaults tonil.- Global attributes are accepted. Additional HTML attributes forwarded to the
<input>element.