Bootstrap 5 One Time Password (OTP) Input
One Time Password (OTP) Input
Create secure and user-friendly one-time password input fields with automatic navigation, paste support, validation, and customizable options for modern authentication flows.
🤖 Looking for the LLM-optimized version? View llm.md
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.
<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.
<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.
<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.
<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.
<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.
<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.
<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.
<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.
<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.
<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-labelattributes - 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:
| Key | Action |
|---|---|
| Arrow Right | Move focus to next input field |
| Arrow Left | Move focus to previous input field |
| Backspace | Delete current character and move to previous field (if empty) |
| Tab | Move to next focusable element (respects linear mode) |
| Shift + Tab | Move to previous focusable element |
| Ctrl + V / Cmd + V | Paste clipboard content and auto-fill fields |
Usage
Heads up! In our documentation, all examples show standard CoreUI implementation. If you are using a Bootstrap-compatible version of CoreUI, remember to use the following changes:
- In the constructor, please use bootstrap instead of coreui. For example,
new bootstrap.Alert(...)instead ofnew coreui.Alert(...) - In events, please use bs instead of coreui, for example
close.bs.alertinstead ofclose.coreui.alert - In data attributes, please use bs instead of coreui. For example,
data-bs-toggle="..."instead ofdata-coreui-toggle="..."
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".
| Name | Type | Default | Description |
|---|---|---|---|
ariaLabel | function | (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 |
autoSubmit | boolean | false | Automatically submit the form when all OTP fields are filled |
disabled | boolean | false | Disable all OTP input fields |
id | string, null | null | ID attribute for the hidden input field |
linear | boolean | true | Enforce sequential input (users must fill fields in order) |
masked | boolean | false | Show input as password (masked characters) |
name | string, null | null | Name attribute for the hidden input field |
placeholder | string, null | null | Placeholder text for input fields. Single character applies to all fields, longer strings apply character-by-character |
readonly | boolean | false | Make OTP input read-only |
required | boolean | false | Makes the input field required for form validation. |
type | string | 'number' | Input validation type: ’number’ for digits only, or any other string for free text |
value | string, number, null | null | Initial value for the OTP input |
Methods
| Method | Description |
|---|---|
clear | Clear all OTP input fields |
reset | Reset OTP input to its initial value |
update | Update 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
| Event | Description |
|---|---|
change.coreui.otp-input | Fired whenever the OTP value changes |
complete.coreui.otp-input | Fired 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:
$form-otp-gap: .125rem; $form-otp-control-width: 2rem; $form-otp-control-padding-y: $input-padding-y; $form-otp-control-padding-x: 0; $form-otp-control-font-family: $input-font-family; $form-otp-control-font-size: $input-font-size; $form-otp-control-font-weight: $input-font-weight; $form-otp-control-line-height: $input-line-height; $form-otp-control-color: $input-color; $form-otp-control-bg: $input-bg; $form-otp-control-border-width: $input-border-width; $form-otp-control-border-color: $input-border-color; $form-otp-control-border-radius: $input-border-radius; $form-otp-control-box-shadow: $input-box-shadow; $form-otp-control-transition: $input-transition; $form-otp-control-focus-color: $input-focus-color; $form-otp-control-focus-bg: $input-focus-bg; $form-otp-control-focus-border-color: $input-focus-border-color; $form-otp-control-focus-box-shadow: $input-focus-box-shadow; $form-otp-control-width-sm: 1.5rem; $form-otp-control-padding-y-sm: $input-padding-y-sm; $form-otp-control-padding-x-sm: 0; $form-otp-control-font-size-sm: $input-font-size-sm; $form-otp-control-border-radius-sm: $input-border-radius-sm; $form-otp-control-width-lg: 2.5rem; $form-otp-control-padding-y-lg: $input-padding-y-lg; $form-otp-control-padding-x-lg: 0; $form-otp-control-font-size-lg: $input-font-size-lg; $form-otp-control-border-radius-lg: $input-border-radius-lg;