Primitives
One-Time Password (OTP) input component with individual character slots for secure authentication codes.
import { Component, signal } from "@angular/core";
import {
NgpInputOtp,
NgpInputOtpInput,
NgpInputOtpSlot,
} from "ng-primitives/input-otp";
@Component({
selector: "app-input-otp",
imports: [NgpInputOtp, NgpInputOtpInput, NgpInputOtpSlot],
template: `
<div
[(ngpInputOtpValue)]="value"
(ngpInputOtpComplete)="onComplete($event)"
ngpInputOtp
>
<input ngpInputOtpInput />
<div class="slots">
<div ngpInputOtpSlot></div>
<div ngpInputOtpSlot></div>
<div ngpInputOtpSlot></div>
<div ngpInputOtpSlot></div>
<div ngpInputOtpSlot></div>
<div ngpInputOtpSlot></div>
</div>
</div>
`,
styles: `
[ngpInputOtp] {
display: flex;
flex-direction: column;
gap: 1rem;
align-items: center;
position: relative;
}
.slots {
display: flex;
gap: 0.5rem;
align-items: center;
}
[ngpInputOtpSlot] {
position: relative;
width: 3rem;
height: 3rem;
border: 2px solid var(--ngp-border);
border-radius: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--ngp-background);
cursor: pointer;
transition: all 0.2s ease;
overflow: hidden;
font-size: 1.25rem;
font-weight: 600;
color: var(--ngp-text-primary);
}
[ngpInputOtp][data-disabled] [ngpInputOtpSlot] {
cursor: default;
opacity: 0.5;
}
[ngpInputOtpSlot]:hover {
border-color: var(--ngp-border-hover);
}
[ngpInputOtpSlot][data-active] {
border-color: var(--ngp-focus-ring);
box-shadow: 0 0 0 1px var(--ngp-focus-ring);
}
[ngpInputOtpSlot][data-placeholder] {
color: var(--ngp-text-placeholder);
}
[ngpInputOtpSlot][data-caret]::after {
content: "";
position: absolute;
width: 1px;
height: 1.5rem;
background-color: var(--ngp-focus-ring);
animation: blink 1s infinite;
}
@keyframes blink {
0%,
50% {
opacity: 1;
}
51%,
100% {
opacity: 0;
}
}
`,
})
export default class InputOtpExample {
readonly value = signal<string>("");
protected onComplete(value: string): void {
console.log("OTP Complete:", value);
}
}
Import the InputOtp primitives from ng-primitives/input-otp.
import { NgpInputOtp, NgpInputOtpInput, NgpInputOtpSlot } from 'ng-primitives/input-otp';
Assemble the input-otp directives in your template.
<div ngpInputOtp [(ngpInputOtpValue)]="otpValue">
<input ngpInputOtpInput />
<div>
<div ngpInputOtpSlot></div>
<div ngpInputOtpSlot></div>
<div ngpInputOtpSlot></div>
</div>
</div>
Create a reusable component that uses the NgpInputOtp directive.
import { Component } from '@angular/core';
import { InputOtp } from './input-otp';
@Component({
selector: 'app-root',
imports: [InputOtp],
template: '<app-input-otp />',
})
export default class App {}
Generate a reusable input-otp component using the Angular CLI.
ng g ng-primitives:primitive input-otp
path: The path at which to create the component file.prefix: The prefix to apply to the generated component selector.componentSuffix: The suffix to apply to the generated component class name.fileSuffix: The suffix to apply to the generated component file name. Defaults to component.exampleStyles: Whether to include example styles in the generated component file. Defaults to true.The following directives are available to import from the ng-primitives/input-otp package:
The root container for the OTP input component.
The current value of the OTP.
The regex pattern for allowed characters.
The input mode for the hidden input.
Function to transform pasted text.
Whether the input-otp is disabled.
The placeholder character to display when a slot is empty.
Event emitted when the value changes.
Event emitted when the OTP is complete (maxLength characters entered).
[ngpInputOtp]ngpInputOtp
The hidden input element that captures user input.
input[ngpInputOtpInput]ngpInputOtpInput
A directive that represents individual character slots. Automatically registers with the parent input OTP and derives its index from registration order.
[ngpInputOtpSlot]ngpInputOtpSlot
| Attribute | Description |
|---|---|
data-slot-index |
The index of this slot. |
data-active |
Added to the active (focused) slot. |
data-filled |
Added to slots that contain a character. |
data-caret |
Added to slots that show the cursor. |
data-placeholder |
Added to slots that should show placeholder text. |
Copyright © 2025 Angular Primitives