Documentation and live examples v1.4.0

otp-angular

Angular OTP inputs for verification codes, Web OTP SMS autofill, resend timers, form validation, loading states, accessibility, and custom OTP UI.

Download & install

Install the package in your Angular project.

Terminal
npm install otp-angular

Usage

Import the standalone component, provide an OtpAngularType config, and handle the value through Angular forms or outputs.

Angular standalone component
import { Component, signal } from '@angular/core';
import { OtpAngular, OtpAngularType } from 'otp-angular';

@Component({
  imports: [OtpAngular],
  template: `
    <otp-angular
      [config]="config()"
      (onAutoSubmit)="verifyOtp($event)"
    />
  `
})
export class LoginComponent {
  config = signal<OtpAngularType>({
    length: 6,
    numbersOnly: true,
    autoSubmit: true,
    autoSubmitValidOnly: true
  });

  verifyOtp(code: string | number | null): void {
    console.log(code);
  }
}

Browser-only paths like focus, clipboard, timers, and Web OTP are guarded for SSR.

Examples

Every row has a working OTP example and the code a developer can copy into an Angular app, including separate Size presets and Variant presets examples.

Reactive forms

Use formControlName with validation, loading, errors, resend events, and parent methods.

Live playgroundVerify login code
New code available in 30 seconds
Form valuenullResend timer-s
Example code
<form [formGroup]="form">
  <otp-angular
    #otpRef
    [config]="config()"
    formControlName="otp"
    (onAutoSubmit)="verifyOtp($event)"
    (onResendTimerChange)="seconds = $event"
  />
</form>

Template-driven forms

Bind directly with [(ngModel)] when a smaller form does not need a FormGroup.

ngModel value: null

Example code
<otp-angular
  [config]="{ length: 4, numbersOnly: true }"
  [(ngModel)]="otp"
/>

Numeric mode

Enable numbersOnly for SMS, banking, and 2FA codes that should reject letters.

Example code
config: OtpAngularType = {
  length: 4,
  numbersOnly: true,
  placeholder: '0'
};

Alphanumeric + uppercase

Use default alphanumeric input and showCaps for invitation codes or backup codes.

-
-
-
-

Try letters and numbers. showCaps converts letters to uppercase.

Example code
config: OtpAngularType = {
  length: 5,
  showCaps: true,
  separator: '-',
  placeholder: 'A'
};

Paste and keyboard

Paste full codes, move with arrows, jump with Home/End, and edit with Delete or Backspace.

Paste a full code, then try ArrowLeft, ArrowRight, Home, End, Delete, and Backspace.

Example code
// Built in behavior:
// paste, Backspace, Delete, Home, End, ArrowLeft, ArrowRight
config: OtpAngularType = {
  length: 6,
  numbersOnly: true
};

Auto-submit valid only

Prevent automatic submit when a paste includes rejected or extra characters.

Clean paste submits.Rejected or extra characters still fill accepted boxes, but do not auto-submit.
Example code
config: OtpAngularType = {
  length: 6,
  numbersOnly: true,
  autoSubmit: true,
  autoSubmitValidOnly: true
};

Loading and error state

Block typing while verifying and show Angular form errors after the control is touched.

Use the first demo controls.Try Start loading, Invalid OTP, OTP expired, then Clear error.
Example code
otpRef.loading.set(true);
otp.markAsTouched();
otp.setErrors({ invalidOtp: true });
otp.setErrors({ otpExpired: true });

Web OTP SMS autofill

Let supported Android Chrome browsers offer SMS one-time-code autofill.

Browser feature.Requires supported Android Chrome, HTTPS, and a correctly formatted SMS.
Example code
config: OtpAngularType = {
  length: 6,
  numbersOnly: true,
  autoSubmit: true,
  autoSubmitValidOnly: true,
  webOtp: true
};

Resend countdown events

Use the built-in timer or mirror every second in your own app UI.

Current timer: -sThe first demo emits onResendTimerChange every second.
Example code
<otp-angular
  [config]="{ length: 6, resend: 30 }"
  (onResendTimerChange)="seconds = $event"
  (onResendAvailable)="sendAgain()"
/>

Public methods

Parent components can fill, clear, focus, focus a specific box, and reset resend.

Example code
otpRef.setValue('123456');
otpRef.clear();
otpRef.focus();
otpRef.focusIndex(3);
otpRef.reset();

Password mask delay

Briefly show newly typed digits before password masking, like banking apps.

Example code
config: OtpAngularType = {
  length: 4,
  numbersOnly: true,
  isPassword: true,
  maskDelay: 700
};

Theme presets

Switch between default, banking, minimal, rounded, underline, glass, light, and dark presets.

Example code
config: OtpAngularType = {
  length: 4,
  theme: 'banking',
  placeholder: '0'
};

Size: sm

Compact OTP boxes for dense forms and side panels.

Use this when the layout needs the sm OTP scale.

Example code
config: OtpAngularType = {
  length: 4,
  size: 'sm',
  placeholder: '0'
};

Size: md

Default size that keeps the current OTP layout familiar.

Use this when the layout needs the md OTP scale.

Example code
config: OtpAngularType = {
  length: 4,
  size: 'md',
  placeholder: '0'
};

Size: lg

Larger boxes for mobile-first login and verification screens.

Use this when the layout needs the lg OTP scale.

Example code
config: OtpAngularType = {
  length: 4,
  size: 'lg',
  placeholder: '0'
};

Variant: box

Default boxed OTP inputs for most forms.

Use this when the OTP input style should be box.

Example code
config: OtpAngularType = {
  length: 4,
  variant: 'box',
  placeholder: '0'
};

Variant: underline

Low-noise bottom-border inputs for quieter forms.

Use this when the OTP input style should be underline.

Example code
config: OtpAngularType = {
  length: 4,
  variant: 'underline',
  placeholder: '0'
};

Variant: filled

Soft filled boxes for dense app forms.

Use this when the OTP input style should be filled.

Example code
config: OtpAngularType = {
  length: 4,
  variant: 'filled',
  placeholder: '0'
};

Variant: outline

Strong outline boxes for high-emphasis verification flows.

Use this when the OTP input style should be outline.

Example code
config: OtpAngularType = {
  length: 4,
  variant: 'outline',
  placeholder: '0'
};

Validation helpers

Use built-in Angular validators for complete, numeric, and exact-length OTP controls.

Validator status: otpIncomplete

Example code
otp = new FormControl('', [
  OtpValidators.complete(6),
  OtpValidators.numeric(),
  OtpValidators.length(6)
]);

Manual error API

Set and clear an OTP error directly from a parent component without touching Angular form errors.

Manual parent-controlled errors.Use the buttons to set or clear the main playground error.
Example code
otpRef.setError('Invalid code');
otpRef.clearError();

Success state

Show a verified state after the server accepts a code.

Success after verification.Toggle the public success signal on the main playground.
Example code
otpRef.success.set(true);

config: OtpAngularType = {
  length: 6,
  successLabel: 'Verified'
};

Auto clear and focus

Clear bad codes and return focus to the first box when setting an error.

This demo uses clearOnError and focusOnClear.

Example code
config: OtpAngularType = {
  length: 6,
  clearOnError: true,
  focusOnClear: true
};

Styling APIs

Pass container classes, input classes, inline styles, or per-input style arrays.

Example code
config: OtpAngularType = {
  containerClass: ['brand-otp'],
  inputClass: ['brand-box', 'brand-box accent'],
  inputStyles: [{ borderColor: '#e1085d' }]
};

Reactive disabled state

Disable the Angular form control and the OTP boxes follow it.

Control state: enabled

Example code
otp.disable();
otp.enable();

Multiple instances

Use more than one OTP component on a page without shared focus, values, or events.

Example code
<otp-angular [config]="config()" [formControl]="first" />
<otp-angular [config]="config()" [formControl]="second" />

Custom input template

Render your own input UI while keeping forms, paste, focus, and keyboard behavior.

-
-
-
Example code
<otp-angular [config]="config()">
  <ng-template otpAngularInputTemplate let-otp>
    <input
      otpAngularInput
      [value]="otp.value"
      [type]="otp.type"
      (input)="otp.handlers.input($event)"
      (keydown)="otp.handlers.keydown($event)"
      (paste)="otp.handlers.paste($event)"
    />
  </ng-template>
</otp-angular>

Themes

Use one config value to move from the default OTP look to banking, minimal, rounded, underline, glass, or dark UI. light remains available as a legacy alias of default.

default

Clean neutral boxes; this is the documented baseline style.

Theme code
theme: 'default'

banking

Stronger borders and focus treatment for secure or finance flows.

Theme code
theme: 'banking'

minimal

Quiet inputs for simple forms where the surrounding UI should lead.

Theme code
theme: 'minimal'

rounded

Soft pill-like boxes for friendly mobile-first verification screens.

Theme code
theme: 'rounded'

underline

Borderless boxes with a bottom rule only.

Theme code
theme: 'underline'

glass

Translucent inputs for modern app surfaces.

Theme code
theme: 'glass'

light

Legacy alias for the default preset; kept for backward compatibility.

Theme code
theme: 'light'

dark

Dark inputs for dark panels and app shells.

Theme code
theme: 'dark'

Configuration parameters

Pass an OtpAngularType config object. The component keeps forms, outputs, and direct parent-control methods in sync.

OptionDefaultWhat it does
length4Number of OTP boxes.
numbersOnlyfalseReject non-numeric characters.
autoSubmitfalseEmit when every box is filled.
autoSubmitValidOnlyfalseOnly auto-submit clean accepted input with no invalid Angular form state.
autoFocusfalseFocus the first box after browser render.
webOtpfalseEnable supported Web OTP SMS autofill.
isPasswordfalseMask input values with password boxes.
maskDelay0Temporarily reveal typed or pasted password-mode characters.
showErrorfalseApply legacy empty-box error styling on blur.
errorMessages{}Override Angular form validation messages.
errorMessageClass''Class applied to the rendered error message.
loadingLabel'Verifying...'Text beside the loading spinner.
loadingContainerClass, loadingSpinnerClass''Classes for the loading row and spinner.
ariaLabel'One-time password'Accessible label for the full OTP group.
inputAriaLabel'One-time password digit {index} of {length}'Accessible label template for each box.
resendAriaLabel'Resend verification code'Accessible label for the resend button.
resendCountdownAriaLabel'Resend verification code available in {seconds} seconds'Live resend countdown announcement.
showCapsfalseConvert letters to uppercase.
containerClass, inputClass''Classes for the OTP container and input boxes.
containerStyles, inputStyles{}Inline styles for the container or inputs; inputStyles can be an array.
placeholder''Placeholder shown in each input.
separator''Text shown between OTP boxes.
resend0Enables the resend countdown when greater than zero.
resendLabel, resendContainerClass, resendLabelClass, resendTimerClass''Resend text and styling hooks.
theme'default'Built-in preset: 'default', 'banking', 'minimal', 'rounded', 'underline', 'glass', 'light', or 'dark'.
size'md'Built-in input size preset: 'sm', 'md', or 'lg'.
variant'box'Built-in input structure preset: 'box', 'underline', 'filled', or 'outline'.
successfalseShows success styling and the success status row.
successLabel'Verified'Success status text shown when success state is active.
clearOnErrorfalseClears the OTP value when setError(message) is called.
focusOnClearfalseFocuses the first box after clear() or clearOnError.

Outputs

Use outputs when you do not want to read the Angular form control directly.

OutputWhen it emits
onInputChangeEmits the current OTP value whenever it changes.
onAutoSubmitEmits the completed OTP value when autoSubmit conditions pass.
onResendTimerChangeEmits remaining resend seconds from the initial value through 0.
onResendAvailableEmits true when the resend action is clicked.

Methods

MethodPurpose
setValue(value)Set the visible OTP value from the parent component.
clear()Clear all boxes and update the Angular form value to null.
focus()Focus the first box when enabled in the browser.
focusIndex(index)Focus a zero-based box index; invalid indexes are safe no-ops.
reset()Restart the resend countdown.
setError(message)Show a manual parent-controlled OTP error.
clearError()Remove only the manual parent-controlled OTP error.
success.set(value)Toggle the public success signal after server verification.

Accessibility / SSR

The component exposes group labels, per-input labels, resend announcements, error announcements, and keyboard-only controls.

Angular 20-22 support
Reactive and template-driven forms
SSR-safe browser guards
No runtime dependency beyond Angular and tslib

Result log

  • readyWaiting for OTP input