Input OTP

Accessible one-time password component with copy paste functionality.

Preview Code
Interactive

Features

  • Copy/paste support.
  • Keyboard navigation.
  • Customizable slot rendering.
  • Works with password managers.
  • Supports numeric and alphanumeric modes.

Installation

Install the component from your command line.

Angular CLInpmpnpmyarnbun
Bash
ng g @ng-cn/core:c input-otp

Anatomy

Import all parts and piece them together.

Typescript
import {
  InputOTP,
  InputOTPGroup,
  InputOTPSlot,
  InputOTPSeparator
} from '@/ui/input-otp';
Html
<InputOTP>
  <InputOTPGroup>
    <InputOTPSlot [index]="0" />
    <InputOTPSlot [index]="1" />
    <InputOTPSlot [index]="2" />
  </InputOTPGroup>
  <InputOTPSeparator />
  <InputOTPGroup>
    <InputOTPSlot [index]="3" />
    <InputOTPSlot [index]="4" />
    <InputOTPSlot [index]="5" />
  </InputOTPGroup>
</InputOTP>

API Reference

Root

Contains all the parts of an input OTP.

PropTypeDefault
value string
The controlled value of the input.
maxLength number 6
Maximum number of characters.
disabled boolean false
When true, prevents the user from interacting with the input.
pattern string "^[0-9]*$"
Pattern for input validation.
inputMode 'numeric' | 'text' | 'decimal' | 'tel' 'numeric'
Input mode for virtual keyboard.
class string
Additional CSS classes to apply.

Data Attributes

AttributeValues
[data-disabled]Present when disabled

Group

Used to group multiple InputOTPSlot components.

PropTypeDefault
class string
Additional CSS classes to apply.

Slot

Renders an individual input slot.

PropTypeDefault
index *number
The index of this slot (0-based).
class string
Additional CSS classes to apply.

Data Attributes

AttributeValues
[data-active]Present when slot is active
[data-filled]Present when slot has a value

Separator

Used to render a separator between slot groups.

PropTypeDefault
class string
Additional CSS classes to apply.

Examples

Basic

A 6-digit OTP input with separator.

Html
<InputOTP [maxLength]="6">
  <InputOTPGroup>
    <InputOTPSlot [index]="0" />
    <InputOTPSlot [index]="1" />
    <InputOTPSlot [index]="2" />
  </InputOTPGroup>
  <InputOTPSeparator />
  <InputOTPGroup>
    <InputOTPSlot [index]="3" />
    <InputOTPSlot [index]="4" />
    <InputOTPSlot [index]="5" />
  </InputOTPGroup>
</InputOTP>

Simple 4-digit

A simple 4-digit OTP without separator.

Html
<InputOTP [maxLength]="4">
  <InputOTPGroup>
    @for (i of [0,1,2,3]; track i) {
      <InputOTPSlot [index]="i" />
    }
  </InputOTPGroup>
</InputOTP>

Controlled

Control the OTP value externally.

Html
// In your component:
otp = signal('');

onComplete(value: string) {
  console.log('OTP completed:', value);
}

// In template:
<InputOTP
  [(value)]="otp"
  [maxLength]="6"
  (onComplete)="onComplete($event)"
>
  <InputOTPGroup>
    @for (i of [0,1,2,3,4,5]; track i) {
      <InputOTPSlot [index]="i" />
    }
  </InputOTPGroup>
</InputOTP>

<p>Current value: {{ otp() }}</p>

With pattern

Alphanumeric OTP with custom pattern.

Html
<InputOTP [maxLength]="6" pattern="^[a-zA-Z0-9]*$" inputMode="text">
  <InputOTPGroup>
    @for (i of [0,1,2,3,4,5]; track i) {
      <InputOTPSlot [index]="i" />
    }
  </InputOTPGroup>
</InputOTP>

Disabled

Disabled state.

Html
<InputOTP [maxLength]="6" [disabled]="true">
  <InputOTPGroup>
    @for (i of [0,1,2,3,4,5]; track i) {
      <InputOTPSlot [index]="i" />
    }
  </InputOTPGroup>
</InputOTP>

Accessibility

Adheres to the OTP/PIN input pattern .

Keyboard Interactions

KeyDescription
0-9 Types the digit into the current slot and moves to next.
Backspace Clears the current slot and moves to previous.
Paste Fills slots with pasted content.