Getting StartedComponentsDesign TokensThemingTheme SynthesizerFrameworksAccessibilityUtilitiesServer RenderingBrowser SupportContributingChangelog App ShellAspect GridAuth ShellCenterClusterContainerDashboard GridDockFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkSpeed DialStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCalloutCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSeparatorSkeletonSpinnerStackVideoVirtual List Activity HeatmapAnimated NumberBadgeChartClockComparisonCountdown TimerData GridData TableDescription ListDiffEvent CalendarGaugeJSON TreeKanbanKey ValueLevel MeterListMeterSparklineStatStepperTableTagTimelineUptimeValue CardWaveform BlockquoteCode BlockGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputOTP InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree Select AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuGuided TourHover CardInline MessageLoading OverlayModalNotification PanelPopoverProgressProgress ToastSheetSnackbarSpotlightToastTooltip
ARC UI ARC Radiant Components
v3.2 Docs Components Tokens Synthesizer
Getting StartedFrameworksServer Rendering Design TokensThemingTheme SynthesizerTypographyUtilities All ComponentsAccessibilityBrowser SupportChangelogContributingStats App ShellAspect GridAuth ShellCenterClusterContainerDashboard GridDockFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkSpeed DialStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCalloutCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSeparatorSkeletonSpinnerStackVideoVirtual List Activity HeatmapAnimated NumberBadgeChartClockComparisonCountdown TimerData GridData TableDescription ListDiffEvent CalendarGaugeJSON TreeKanbanKey ValueLevel MeterListMeterSparklineStatStepperTableTagTimelineUptimeValue CardWaveform BlockquoteCode BlockGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputOTP InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree Select AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuGuided TourHover CardInline MessageLoading OverlayModalNotification PanelPopoverProgressProgress ToastSheetSnackbarSpotlightToastTooltip

OTP Input

A one-time password input that renders a row of individual character boxes with auto-advance, paste support, and configurable length and input type.

Components OTP Input
input interactive
<arc-otp-input>

Overview

OTPInput provides a specialized multi-box code entry field commonly used for verification codes, two-factor authentication, and PIN inputs. It renders a configurable number of individual input boxes (defaulting to 6) in a horizontal row, each accepting a single character. As the user types, focus automatically advances to the next box, and pressing Backspace on an empty box moves focus backward and clears the previous character — creating a smooth, uninterrupted typing flow. The component supports two input modes via the `type` prop. The default `number` mode filters out non-digit characters and sets `inputmode="numeric"` for mobile keyboard optimisation. Setting `type="text"` allows any character, suitable for alphanumeric verification codes. Each box uses a monospace font at 20px for clear character visibility, with an accent-primary caret and focus ring to highlight the active input position. Paste handling is built in — pasting a code into any box distributes the characters across subsequent boxes and advances focus to the end of the pasted content. The component fires `arc-input` on every character addition or removal, with the partial concatenated value in the event detail, and `arc-change` once every box is filled — the commit for a fixed-length code. Arrow keys, Home, and End provide horizontal navigation across boxes, and the `autocomplete="one-time-code"` attribute enables browser autofill from SMS or authenticator apps.

Guidelines

When to use

  • Set `length` to match the expected code length from your authentication backend
  • Use `type="number"` for numeric-only codes to get the mobile numeric keyboard
  • Listen for `arc-change` to auto-submit — it fires only once the code is complete
  • Place OTPInput in a focused, distraction-free context like a verification step
  • Provide a clear label or heading above the input explaining what code to enter

When not to use

  • Do not use OTPInput for general text entry — it is designed specifically for short codes
  • Do not set `length` higher than 8 — very long code inputs become unwieldy on mobile screens
  • Do not use `type="text"` when the code is purely numeric — the wrong keyboard will appear on mobile
  • Do not place multiple OTP Inputs on the same page — it creates confusion about which code to enter
  • Avoid removing the component from the DOM before the user has finished entering the code

Features

  • Row of individual character boxes with configurable `length` (default 6)
  • Auto-advance: focus moves to the next box on character entry
  • Backspace moves focus backward and clears the previous box when the current box is empty
  • Paste support: distributes pasted characters across boxes and advances focus
  • Two input modes: `number` (digits only with numeric keyboard) and `text` (any character)
  • Arrow key, Home, and End navigation across individual boxes
  • Browser autofill support via `autocomplete="one-time-code"` on each input
  • Fires `arc-input` on every character change and `arc-change` once the code is complete

Preview

Usage

This component requires JavaScript. No pure HTML/CSS version is available — use the Web Component directly or a framework wrapper.

<arc-otp-input length="6" type="number"></arc-otp-input>
import { OtpInput } from '@arclux/arc-ui-react';

export default function Example() {
  return (
    <OtpInput length={6} type="number" />
  );
}
<script setup>
import { OtpInput } from '@arclux/arc-ui-vue';
</script>

<template>
  <OtpInput :length="6" type="number" />
</template>
<script>
  import { OtpInput } from '@arclux/arc-ui-svelte';
</script>

<OtpInput length={6} type="number" />
import { Component } from '@angular/core';
import { OtpInput } from '@arclux/arc-ui-angular';

@Component({
  imports: [OtpInput],
  template: `
    <arc-otp-input [length]="6" type="number"></arc-otp-input>
  `,
})
export class MyComponent {}
import { OtpInput } from '@arclux/arc-ui-solid';

export default function Example() {
  return (
    <OtpInput length={6} type="number" />
  );
}
import { OtpInput } from '@arclux/arc-ui-preact';

export default function Example() {
  return (
    <OtpInput length={6} type="number" />
  );
}

API

size 'sm' | 'md' | 'lg' 'md'
Control size. `md` is the default; `sm` and `lg` scale the digit boxes.
length number 6
Number of individual character boxes to render. Reflected as an attribute.
value string ''
The concatenated value of all boxes. Reflected as an attribute and updated on every input.
name string ''
disabled boolean false
Disables all input boxes, reducing opacity to 40% and blocking pointer events.
type 'number' | 'text' 'number'
Input mode. `number` filters non-digits and uses the numeric keyboard; `text` allows any character.
readonly boolean false
Prevents typing, pasting, and clearing digits while the boxes stay focusable and the value still submits.
formAssociated boolean true
properties object { required: { type: Boolean, reflect: true }, readonly: { type: Boolean, reflect: true }, }
Lit merges static properties up the prototype chain, so every consumer gets these without declaring them. `required` participates in constraint validation below; `readonly` reflects for styling and is enforced by each component's interaction handlers (the mixin can't know which gestures mutate state).
autoValidates boolean true
Components that run their own constraint-validation logic (pattern checks, range checks) opt out of the automatic required sync by overriding this to false, and own the whole validity flag set instead.
form
validity
validationMessage
required boolean false

Events

arc-input detail: { value: string }
Fired on every digit entered or deleted, with the partial value.
arc-change detail: { value: string }
Fired when the code is complete — every box filled. That is the commit for a fixed-length code.

See Also