Separator
Use `FrInputOtpSeparator` to divide a code into readable groups.
Icons by @ng-icons/tabler-icons
The component library does not provide icons.
One-time password input with grouped slots, separators, paste support, patterns, and reactive forms compatibility.
Preview
Value: 123456
TS
import { FR_INPUT_OTP_PATTERN_DIGITS_AND_CHARS, FrInputOtpModule } from '@frame-ui-ng/components/input-otp';TS
import { FormControl } from '@angular/forms';
readonly code = new FormControl('');HTML
<frame-input-otp [formControl]="code" [maxLength]="6">
<div frInputOtpGroup>
<div frInputOtpSlot [index]="0"></div>
<div frInputOtpSlot [index]="1"></div>
<div frInputOtpSlot [index]="2"></div>
<div frInputOtpSlot [index]="3"></div>
<div frInputOtpSlot [index]="4"></div>
<div frInputOtpSlot [index]="5"></div>
</div>
</frame-input-otp>Use `FrInputOtpSeparator` to divide a code into readable groups.
Disable the reactive form control to disable the OTP input.
Input OTP implements ControlValueAccessor and works directly with Angular reactive forms.
Value: 123456
Angular validation state drives the error treatment and clears when the value becomes valid.
Enter all 6 digits.
Use a shorter `maxLength` for PIN-code patterns.
Use `FR_INPUT_OTP_PATTERN_DIGITS_AND_CHARS` to accept letters and numbers.
Pair Input OTP with Field and Angular validators for full form flows.
Input OTP inherits text direction from its container.
Inspect the root, slot, active slot, group, and separator tokens.
Input OTP builds its visible slots on top of the same surface decisions as FrInput, then adds slot, group, and separator tokens for segmented code entry.
SCSS
--frame-input-otp-gap: 0.5rem;
--frame-input-otp-group-gap: 0;
--frame-input-otp-slot-size: 2.5rem;
--frame-input-otp-slot-radius: var(--frame-input-root-radius);
--frame-input-otp-slot-bg: var(--frame-input-root-bg);
--frame-input-otp-slot-color: var(--frame-input-root-color);
--frame-input-otp-slot-border: var(--frame-input-root-border);
--frame-input-otp-slot-font-size: 1rem;
--frame-input-otp-slot-font-weight: 500;
--frame-input-otp-slot-focus-border: var(--frame-input-root-focus-border);
--frame-input-otp-slot-focus-shadow: var(--frame-input-root-focus-shadow);
--frame-input-otp-slot-invalid-border: var(--frame-input-root-invalid-border);
--frame-input-otp-slot-invalid-shadow: var(--frame-input-root-invalid-shadow);
--frame-input-otp-slot-disabled-bg: var(--frame-input-root-disabled-bg);
--frame-input-otp-slot-disabled-color: var(--frame-input-root-disabled-color);
--frame-input-otp-slot-disabled-opacity: var(--frame-input-root-disabled-opacity);
--frame-input-otp-slot-placeholder-color: var(--frame-input-root-placeholder-color);
--frame-input-otp-separator-color: var(--frame-muted-foreground);
--frame-input-otp-separator-size: 0.375rem;