Bootstrap 5 One Time Password (OTP) Input

One Time Password (OTP) Input

CoreUI PRO
This component is part of CoreUI PRO – a powerful UI library with over 250 components and 25+ templates, designed to help you build modern, responsive apps faster. Fully compatible with Angular, Bootstrap, React.js, and Vue.js.

Create secure and user-friendly one-time password input fields with automatic navigation, paste support, validation, and customizable options for modern authentication flows.

Available in Other JavaScript Frameworks

CoreUI Bootstrap 5 One Time Password (OTP) Input is also available for Angular, React, and Vue. Explore framework-specific implementations below:

Example

Use the form-otp wrapper with data-coreui-toggle="otp" to create an one-time password input field with automatic character navigation and validation.

html
<label for="basicOTP" class="form-label">Enter OTP Code</label>
<div class="form-otp" data-coreui-toggle="otp" data-coreui-id="basicOTP" data-coreui-name="otp">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
</div>

One-time password types

The one-time password input supports different input types for various use cases.

html
<div class="mb-3">
  <label class="form-label">Numeric OTP (default)</label>
  <div class="form-otp" data-coreui-toggle="otp" data-coreui-type="number">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
  </div>
</div>
<div class="mb-3">
  <label class="form-label">Text OTP</label>
  <div class="form-otp" data-coreui-toggle="otp" data-coreui-type="text">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
  </div>
</div>
<div>
  <label class="form-label">Masked OTP (hidden characters)</label>
  <div class="form-otp" data-coreui-toggle="otp" data-coreui-masked="true">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
  </div>
</div>

Placeholders

Provide visual hints to users by setting placeholder text for OTP input fields. You can use a single character for all fields or specify different placeholders for each field.

html
<div class="mb-3">
  <label class="form-label">Single character placeholder</label>
  <div class="form-otp" data-coreui-toggle="otp" data-coreui-placeholder="0">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
  </div>
</div>
<div class="mb-3">
  <label class="form-label">Different placeholders per field</label>
  <div class="form-otp" data-coreui-toggle="otp" data-coreui-placeholder="123456">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
  </div>
</div>
<div>
  <label class="form-label">Letter placeholders</label>
  <div class="form-otp" data-coreui-toggle="otp" data-coreui-type="text" data-coreui-placeholder="ABCDEF">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
  </div>
</div>

Pre-filled values

Set initial values using the data-coreui-value attribute.

html
<label class="form-label">OTP with pre-filled value</label>
<div class="form-otp" data-coreui-toggle="otp" data-coreui-value="123456">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
</div>

Input modes

Control user input behavior with linear and non-linear modes.

html
<div class="mb-3">
  <label class="form-label">Linear mode (sequential input)</label>
  <div class="form-otp" data-coreui-toggle="otp" data-coreui-linear="true">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
  </div>
</div>
<div>
  <label class="form-label">Non-linear mode (free navigation)</label>
  <div class="form-otp" data-coreui-toggle="otp" data-coreui-linear="false">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
  </div>
</div>

Auto-submit

Enable automatic form submission when all one-time password fields are completed.

html
<form>
  <label class="form-label">Auto-submit OTP</label>
  <div class="form-otp" data-coreui-toggle="otp" data-coreui-auto-submit="true">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
  </div>
</form>

Custom layouts

Create custom one-time password layouts with separators and different field counts.

-
html
<div class="mb-3">
  <label class="form-label">6-digit OTP with separators</label>
  <div class="form-otp" data-coreui-toggle="otp">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <div class="px-2 text-body-tertiary fw-bold">-</div>
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
  </div>
</div>
<div class="mb-3">
  <label class="form-label">9-digit OTP with separators</label>
  <div class="form-otp" data-coreui-toggle="otp">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <div class="px-2 text-body-tertiary fw-bold">•</div>
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <div class="px-2 text-body-tertiary fw-bold">•</div>
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
  </div>
</div>
<div>
  <label class="form-label">4-digit PIN</label>
  <div class="form-otp" data-coreui-toggle="otp" data-coreui-masked="true">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
  </div>
</div>

Sizing variants

One-time password input supports different sizes. You may choose from small, normal (default), and large inputs to match our similarly sized text inputs. To adjust the size of a component, use .form-otp-lg or .form-otp-sm.

html
<div class="mb-3">
  <label class="form-label">Large OTP input</label>
  <div class="form-otp form-otp-lg" data-coreui-toggle="otp">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
  </div>
</div>
<div class="mb-3">
  <label class="form-label">Default OTP input</label>
  <div class="form-otp" data-coreui-toggle="otp">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
  </div>
</div>
<div>
  <label class="form-label">Small OTP input</label>
  <div class="form-otp form-otp-sm" data-coreui-toggle="otp">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
    <input class="form-otp-control">
  </div>
</div>

Disabled state

Disable the entire one-time password input by adding the data-coreui-disabled="true" attribute.

html
<label class="form-label">Disabled OTP input</label>
<div class="form-otp" data-coreui-toggle="otp" data-coreui-disabled="true" data-coreui-value="123456">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
</div>

Readonly state

Use the data-coreui-readonly="true" attribute to make the one-time password input non-editable but still selectable.

html
<label class="form-label">Readonly OTP input</label>
<div class="form-otp" data-coreui-toggle="otp" data-coreui-readonly="true" data-coreui-value="123456">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
</div>

Accessibility

The one-time password input component is designed with accessibility in mind and follows WCAG guidelines for form inputs.

  • ARIA Labels: Each input field automatically receives descriptive aria-label attributes
  • Role Attribute: The container has role="group" to indicate related form controls
  • Keyboard Navigation: Full keyboard support with arrow keys, tab, and backspace
  • Screen Reader Support: Clear announcements when values change or validation occurs
  • Focus Management: Automatic focus handling for seamless navigation

Customizing accessibility

You can customize the aria-label generation function to provide more specific descriptions:

const otp = new coreui.OTPInput(element, {
  ariaLabel: (index, total) => `Enter digit ${index + 1} of your ${total}-digit verification code`
})

Keyboard support

The one-time password input component provides comprehensive keyboard navigation support:

KeyAction
Arrow RightMove focus to next input field
Arrow LeftMove focus to previous input field
BackspaceDelete current character and move to previous field (if empty)
TabMove to next focusable element (respects linear mode)
Shift + TabMove to previous focusable element
Ctrl + V / Cmd + VPaste clipboard content and auto-fill fields

Usage

Via data attributes

The simplest way to use the one-time password input is through data attributes. Add data-coreui-toggle="otp" to a container with .form-otp class containing .form-otp-control inputs.

<div class="form-otp" data-coreui-toggle="otp">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
  <input class="form-otp-control">
</div>

Via JavaScript

Create one-time password inputs programmatically with JavaScript:

const otpElement = document.querySelector('.form-otp')
const otp = new coreui.OTPInput(otpElement, {
  type: 'number',
  autoSubmit: true,
  linear: true,
  masked: false
})

Options

Options can be passed via data attributes or JavaScript. For data attributes, append the option name to data-coreui-, as in data-coreui-type="number".

PropertyTypeDefault
ariaLabelfunction(index, total) => Digit ${index + 1} of ${total}

Function to generate aria-label for each input field. Receives current index (0-based) and total number of inputs

autoSubmitbooleanfalse

Automatically submit the form when all OTP fields are filled

disabledbooleanfalse

Disable all OTP input fields

idstring, nullnull

ID attribute for the hidden input field

linearbooleantrue

Enforce sequential input (users must fill fields in order)

maskedbooleanfalse

Show input as password (masked characters)

namestring, nullnull

Name attribute for the hidden input field

placeholderstring, nullnull

Placeholder text for input fields. Single character applies to all fields, longer strings apply character-by-character

readonlybooleanfalse

Make OTP input read-only

requiredbooleanfalse

Makes the input field required for form validation.

typestring'number'

Input validation type: ‘number’ for digits only, or any other string for free text

valuestring, number, nullnull

Initial value for the OTP input

Methods

MethodDescription
clearClear all OTP input fields
resetReset OTP input to its initial value
updateUpdate the OTP input configuration
const otp = coreui.OTPInput.getInstance(document.querySelector('.form-otp'))
otp.clear() // Clear all fields
otp.reset() // Reset to initial value
otp.update({ type: 'number', masked: true }) // Update configuration

Events

EventDescription
change.coreui.otp-inputFired whenever the OTP value changes
complete.coreui.otp-inputFired when all OTP fields are filled
document.addEventListener('change.coreui.otp-input', event => {
  // eslint-disable-next-line no-console
  console.log('OTP value changed:', event.value)
})

document.addEventListener('complete.coreui.otp-input', event => {
  // eslint-disable-next-line no-console
  console.log('OTP completed:', event.value)
})

Customizing

SASS variables

Customize the appearance of the one-time password input using the following SASS variables:

scss
$form-otp-gap:                         .125rem !default;
$form-otp-control-width:               2rem !default;
$form-otp-control-padding-y:           $input-padding-y !default;
$form-otp-control-padding-x:           0 !default;
$form-otp-control-font-family:         $input-font-family !default;
$form-otp-control-font-size:           $input-font-size !default;
$form-otp-control-font-weight:         $input-font-weight !default;
$form-otp-control-line-height:         $input-line-height !default;
$form-otp-control-color:               $input-color !default;
$form-otp-control-bg:                  $input-bg !default;
$form-otp-control-border-width:        $input-border-width !default;
$form-otp-control-border-color:        $input-border-color !default;
$form-otp-control-border-radius:       $input-border-radius !default;
$form-otp-control-box-shadow:          $input-box-shadow !default;
$form-otp-control-transition:          $input-transition !default;
$form-otp-control-focus-color:         $input-focus-color !default;
$form-otp-control-focus-bg:            $input-focus-bg !default;
$form-otp-control-focus-border-color:  $input-focus-border-color !default;
$form-otp-control-focus-box-shadow:    $input-focus-box-shadow !default;

$form-otp-control-width-sm:            1.5rem !default;
$form-otp-control-padding-y-sm:        $input-padding-y-sm !default;
$form-otp-control-padding-x-sm:        0 !default;
$form-otp-control-font-size-sm:        $input-font-size-sm !default;
$form-otp-control-border-radius-sm:    $input-border-radius-sm !default;

$form-otp-control-width-lg:            2.5rem !default;
$form-otp-control-padding-y-lg:        $input-padding-y-lg !default;
$form-otp-control-padding-x-lg:        0 !default;
$form-otp-control-font-size-lg:        $input-font-size-lg !default;
$form-otp-control-border-radius-lg:    $input-border-radius-lg !default;