Skip to main content

OTP input

One-time passwords, PIN codes and verification codes, in a single accessible input drawn as separate slots.

Bootstrap’s otp input docs describe the markup and CSS.

How it works

Put one bsOtpInput in a bsOtp. Screen readers, password managers and SMS autofill see one ordinary text input, with autocomplete="one-time-code", drawn as a slot per character. Its maxlength sets the number of slots. Typing overwrites the slot at the caret, clicking a slot moves to it, and pasting 123-456 drops the dash. Bind the input like any text input.

Value: empty

<div bsOtp (complete)="completed.set($event)">
  <input bsOtpInput maxlength="6" aria-label="Verification code" [formControl]="code" />
</div>
<p class="mt-3 mb-0 fg-3">
  Value: {{ code.value || 'empty' }}
  @if (completed()) {
    · completed with {{ completed() }}
  }
</p>

Connected inputs

Set connected to merge the slots into one field with shared borders.

HTML
<div bsOtp connected>
  <input bsOtpInput maxlength="6" aria-label="Verification code" />
</div>

Four-digit PIN

Use a smaller maxlength for shorter codes.

HTML
<div bsOtp connected>
  <input bsOtpInput maxlength="4" aria-label="PIN" />
</div>

With separator

Set groups to split the slots, for codes like 123-456. The separator is decorative and never part of the value; change it with separator.

HTML
<div bsOtp [groups]="[3, 3]">
  <input bsOtpInput maxlength="6" aria-label="Verification code" />
</div>

Sizes

Set size to sm or lg.

HTML
<div class="vstack gap-3">
  <div bsOtp size="sm">
    <input bsOtpInput maxlength="6" aria-label="Small verification code" />
  </div>
  <div bsOtp size="lg">
    <input bsOtpInput maxlength="6" aria-label="Large verification code" />
  </div>
</div>

Alphanumeric and masking

Only digits are accepted by default. Set type to alphanumeric or alpha to accept letters, which also changes the input’s inputmode and pattern. Set mask to show dots while keeping a text input, so the numeric keyboard and autofill still work.

HTML
<div class="vstack gap-3">
  <div bsOtp connected type="alphanumeric">
    <input bsOtpInput maxlength="6" aria-label="Alphanumeric code" />
  </div>
  <div bsOtp connected mask>
    <input bsOtpInput maxlength="6" aria-label="Masked code" />
  </div>
</div>

Disabled

Disable the input, or its form control.

<div bsOtp connected>
  <input bsOtpInput maxlength="6" aria-label="Verification code" [formControl]="code" />
</div>

Validation

The slots follow the input’s validation state: from its form control, or set validation on the input.

HTML
<div class="vstack gap-3">
  <div bsOtp connected>
    <input
      bsOtpInput
      maxlength="6"
      value="123456"
      validation="valid"
      aria-label="Valid verification code" />
  </div>
  <div bsOtp connected>
    <input
      bsOtpInput
      maxlength="6"
      value="123"
      validation="invalid"
      aria-label="Invalid verification code" />
  </div>
</div>

With form field

In a bsFormField, the label and help text are linked to the input, and feedback shows when the code is invalid.

Enter the 6-digit code sent to your phone.
Enter all 6 digits.
<div bsFormField>
  <label bsFormLabel>Verification code</label>
  <div bsOtp>
    <input bsOtpInput maxlength="6" [formControl]="code" />
  </div>
  <small bsFormText>Enter the 6-digit code sent to your phone.</small>
  <div bsInvalidFeedback>Enter all 6 digits.</div>
</div>

API

BsOtp

Selector: div[bsOtp] · Exported as: bsOtp

Inputs

NameTypeDefaultDescription
type'numeric' | 'alphanumeric' | 'alpha''numeric'Characters the input accepts.
maskbooleanfalseShows a dot instead of each character.
groupsnumber[] | nullnullGroup sizes, with a separator between groups.
separatorstring'·'Character shown between groups.
connectedbooleanfalseMerges the slots into one field.
size'sm' | 'lg' | nullnullSize of the slots.

Outputs

NameTypeDescription
completestringEmits the code when every slot is filled.

BsOtpInput

Selector: input[bsOtpInput] · Exported as: bsOtpInput

Inputs

NameTypeDefaultDescription
maxlengthnumber6Number of characters and slots.
autocompletestring'one-time-code'The input’s autocomplete.
idstringgeneratedElement id. Generated when not set, and used for the field’s label.
validation'auto' | 'valid' | 'invalid' | 'none''auto'Validation styles. auto follows the bound Angular form control.

Methods

NameTypeDescription
focus()voidFocuses the input on the first empty slot.
clear()voidClears the value and focuses the input.