Skip to content

OTP Input

A segmented one-time password input that renders individual cells for each digit. Auto-advances focus between cells, supports paste, Backspace navigation, and fires completion events.

Basic Usage

html
<ore-otp-input label="Verification code" color="primary"></ore-otp-input>

Listen for completion — use the complete event (not change) to trigger auto-submission after the last cell is filled. Always provide a label attribute to give context (e.g. "Verification code").

html
<ore-otp-input id="otp" label="Enter OTP" color="primary"></ore-otp-input>

<script type="module">
  import '@vielzeug/refine';

  document.getElementById('otp').addEventListener('complete', (e) => {
    console.log('OTP complete:', e.detail.value);
  });
</script>

Length

Keep length at 4–8 cells — more cells increase cognitive load.

PreviewCode
RTL
html
<ore-otp-input label="4-digit PIN" length="4" color="primary"></ore-otp-input>
<ore-otp-input label="6-digit OTP (default)" length="6" color="primary"></ore-otp-input>
<ore-otp-input label="8-digit code" length="8" color="primary"></ore-otp-input>

Types

Avoid using alphanumeric for numeric-only codes (e.g. SMS OTPs) — numeric triggers the numeric keyboard on mobile.

PreviewCode
RTL
html
<ore-otp-input label="Numeric (default)" type="numeric" color="primary"></ore-otp-input>
<ore-otp-input label="Alphanumeric" type="alphanumeric" color="secondary"></ore-otp-input>

Masked Input

Use masked to hide the entered values. Always use masked for PINs and security codes to prevent shoulder-surfing.

PreviewCode
RTL
html
<ore-otp-input label="PIN" masked color="primary"></ore-otp-input>

With Separator

Use separator to add a visual divider between cells.

PreviewCode
RTL
html
<ore-otp-input label="With separator (6 cells)" separator color="primary"></ore-otp-input>
<ore-otp-input label="Masked with separator" separator masked length="4" color="secondary"></ore-otp-input>

Sizes

PreviewCode
RTL
html
<ore-otp-input label="Small" size="sm" color="primary"></ore-otp-input>
<ore-otp-input label="Medium" size="md" color="primary"></ore-otp-input>
<ore-otp-input label="Large" size="lg" color="primary"></ore-otp-input>

Colors

PreviewCode
RTL
html
<ore-otp-input color="primary"></ore-otp-input>
<ore-otp-input color="secondary"></ore-otp-input>
<ore-otp-input color="success"></ore-otp-input>
<ore-otp-input color="warning"></ore-otp-input>
<ore-otp-input color="error"></ore-otp-input>

Variants

PreviewCode
RTL
html
<ore-otp-input></ore-otp-input>
<ore-otp-input variant="flat"></ore-otp-input>
<ore-otp-input variant="bordered" color="primary"></ore-otp-input>
<ore-otp-input variant="outline"></ore-otp-input>
<ore-otp-input variant="ghost"></ore-otp-input>

Disabled

PreviewCode
RTL
html
<ore-otp-input label="Disabled" disabled value="123456" color="primary"></ore-otp-input>

API Reference

Attributes

AttributeTypeDefaultDescription
lengthnumber6Number of input cells
type'numeric' | 'alphanumeric''numeric'Allowed character type
valuestring''Current value (string of all cells concatenated)
maskedbooleanfalseRender cells as hidden characters
separatorbooleanfalseShow a visual divider between cells
disabledbooleanfalseDisable all cells
labelstringAccessible label for the group
namestringForm field name
color'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'Focus ring / active cell color
size'sm' | 'md' | 'lg''md'Cell size
variant'solid' | 'flat' | 'bordered' | 'outline' | 'ghost''solid'Visual style variant

Events

EventDetailDescription
change{ value: string, complete: boolean }Fired on every cell input
complete{ value: string }Fired when all cells have been filled

CSS Custom Properties

PropertyDescription
--otp-cell-sizeWidth and height of each cell
--otp-cell-gapGap between cells
--otp-cell-font-sizeFont size inside each cell
--otp-cell-radiusCell border radius
--otp-cell-bgCell background color
--otp-cell-border-colorDefault cell border color
--otp-cell-focus-borderFocused border/caret color
--otp-cell-hover-bgCell background on hover (flat/ghost variants)
--otp-cell-hover-border-colorCell border on hover (flat/bordered variants)
--otp-cell-focus-bgCell background when focused (flat variant)
--otp-cell-focus-border-colorCell border when focused (flat variant)

Accessibility

The OTP input component follows WCAG 2.1 Level AA standards. It renders as a <fieldset> with a <legend> derived from the label attribute, so always provide a label to ensure screen readers announce the group correctly. Each cell input has autocomplete="one-time-code" set automatically, and aria-disabled reflects the disabled state.

Keyboard navigation is fully supported: focus auto-advances to the next cell on valid input, Backspace moves back and clears the cell, Tab moves focus out of the group, and paste fills all cells at once.

Do not auto-submit without giving users a chance to review — show a confirmation step before sending.

  • Input — plain single-line input field