概览
OTP(一次性密码)输入是双因素认证、验证码和 PIN 输入的常见模式。Bootstrap 的 OTP 输入基于一个 单独的真实文本字段,视觉上呈现为独立的数字槽。这使控件保持简单且完全可访问——屏幕阅读器、密码管理器和短信自动填充都将其视为普通文本输入——同时仍然提供了熟悉的多框外观。
- 一个可访问的控件:整个输入字段由单个
<input>支撑,因此辅助技术会宣布一个字段,而不是每位数字各自一个 - 浏览器自动填充:支持
autocomplete="one-time-code"用于短信/电子邮件验证码自动填充 - 粘贴支持:可以粘贴完整的验证码——甚至像
123-456这样的格式化验证码,额外字符会自动被去掉 - 点击编辑:点击任意位置即可跳转;输入时会直接覆盖该位置的数字,而不会推动其他数字
- 键盘导航:所有原生文本编辑功能(输入、箭头移动、退格、删除、选择)开箱即用
- 掩码和类型:可选择掩码显示数值,并限制输入为数字、字母数字或字母字符
OTP 输入基于 表单控件 构建,并共享其尺寸标记。
它是如何工作的
将单个 <input> 包裹在带有 .otp 的容器中,并添加 data-bs-otp 以启用 JavaScript。该插件读取输入的 maxlength 来确定要渲染的插槽数量,将真实输入隐藏在透明覆盖样式后,并为每个字符绘制一个 .otp-slot。使用 aria-label 或关联的 <label> 为输入提供可访问的名称。
<div class="otp" data-bs-otp>
<input type="text" class="otp-input" maxlength="6" aria-label="Verification code">
</div>连接的输入
添加 .otp-connected 将插槽合并为具有共享边界的单一整体字段。
<div class="otp otp-connected" data-bs-otp>
<input type="text" class="otp-input" maxlength="6" aria-label="Verification code">
</div>四位数PIN码
将输入的maxlength设置为控制槽的数量——对于像4位数PIN这样的短代码,使用较少的槽。
<div class="otp otp-connected" data-bs-otp>
<input type="text" class="otp-input" maxlength="4" aria-label="PIN">
</div>带分隔符
使用 data-bs-groups 和一组分组大小的数组,将槽拆分为由可视分隔符分隔的组——对于像 "123-456" 这样的代码非常方便。分隔符是装饰性的,永远不会成为数值的一部分。
<div class="otp" data-bs-otp data-bs-groups="[3,3]">
<input type="text" class="otp-input" maxlength="6" aria-label="Verification code">
</div>尺寸
向容器中添加 .otp-sm 或 .otp-lg 以更改插槽大小。
<div class="otp otp-sm mb-3" data-bs-otp>
<input type="text" class="otp-input" maxlength="6" aria-label="Small verification code">
</div>
<div class="otp otp-lg" data-bs-otp>
<input type="text" class="otp-input" maxlength="6" aria-label="Large verification code">
</div>字母数字与掩码
默认情况下仅接受数字。将 data-bs-type 设置为 alphanumeric 或 alpha 可接受字母,将 data-bs-mask="true" 设置为在保持为普通文本字段的同时隐藏输入的值(没有 type="password",因此数字键盘和自动填充仍然可用)。
<div class="otp otp-connected mb-3" data-bs-otp data-bs-type="alphanumeric">
<input type="text" class="otp-input" maxlength="6" aria-label="Alphanumeric code">
</div>
<div class="otp otp-connected" data-bs-otp data-bs-mask="true">
<input type="text" class="otp-input" maxlength="6" aria-label="Masked code">
</div>残疾
向输入添加 disabled 属性以防止交互。
<div class="otp otp-connected" data-bs-otp>
<input type="text" class="otp-input" maxlength="6" aria-label="Verification code" disabled>
</div>验证
在容器中添加 .is-valid 或 .is-invalid 以显示验证状态。
<div class="otp otp-connected is-valid mb-3" data-bs-otp>
<input type="text" class="otp-input" maxlength="6" value="123456" aria-label="Verification code">
</div>
<div class="otp otp-connected is-invalid" data-bs-otp>
<input type="text" class="otp-input" maxlength="6" value="123" aria-label="Verification code">
</div>带表单标签
将 <label> 与输入关联,并为更好的可访问性添加包含 aria-describedby 的帮助文本。
<div class="vstack gap-2">
<label class="form-label" for="otpCode">Verification code</label>
<div class="otp" data-bs-otp>
<input type="text" class="otp-input" id="otpCode" maxlength="6" aria-describedby="otpHelp">
</div>
<div id="otpHelp" class="form-text">Enter the 6-digit code sent to your phone.</div>
</div>用法
通过数据属性
将 data-bs-otp 添加到包裹单个 <input> 的容器中,以自动初始化 OTP 输入行为。
| 属性 | 描述 |
|---|---|
data-bs-otp | 在容器上初始化 OTP 输入。 |
data-bs-length | 槽位数量。默认为输入的数量 maxlength. |
data-bs-type | numeric (默认), alphanumeric,或者 alpha. |
data-bs-mask | 什么时候 true在每个格子中用点来掩盖输入的值。 |
data-bs-groups | 组大小的数组(例如 [3,3]) 在组之间插入分隔符。 |
data-bs-separator | 用于分组之间的分隔符的字符。 |
<div class="otp" data-bs-otp>
<input type="text" class="otp-input" maxlength="6" aria-label="Verification code">
</div>
通过 JavaScript
使用 JavaScript 手动初始化:
const otpElement = document.querySelector('.otp')
const otpInput = new bootstrap.OtpInput(otpElement)
依赖项
如果你从源代码构建 Bootstrap 的 JS,OTP 输入插件需要以下 JavaScript 文件:
| 文件 | 描述 |
|---|---|
js/src/otp-input.ts | 主 OTP 输入组件 |
js/src/base-component.ts | 基础组件类 |
js/src/dom/data.ts | 元素数据存储 |
js/src/dom/event-handler.ts | 事件处理工具 |
js/src/dom/manipulator.ts | 数据属性操作 |
js/src/dom/selector-engine.ts | DOM选择器工具 |
js/src/util/config.ts | 配置基类 |
js/src/util/index.ts | 核心实用功能 |
选项
选项可以通过数据属性或 JavaScript 传递:
| 名称 | 类型 | 默认 | 描述 |
|---|---|---|---|
length | 数字, 空 | null | 插槽数量。什么时候 null,它是从输入中读取的 maxlength. |
type | string | 'numeric' | 允许的字符: numeric, alphanumeric,或者 alpha. 集合 inputmode 和 pattern 因此。 |
mask | boolean | false | 如果 true,插槽显示一个点(•)而不是输入的字符。 |
groups | 数组, 空 | null | 用于插入分隔符的组大小(例如 [3, 3]). |
separator | string | '·' | 字符在组之间呈现。 |
方法
| 方法 | 描述 |
|---|---|
getValue() | 以字符串形式返回完整的 OTP 值。 |
setValue(value) | 设置值,并根据配置的类型进行清理。 |
clear() | 清除值并聚焦输入框。 |
focus() | 聚焦输入框,并将光标置于最后一个字符之后。 |
dispose() | 销毁组件实例并移除生成的槽。 |
const otpElement = document.querySelector('.otp')
const otpInput = bootstrap.OtpInput.getOrCreateInstance(otpElement)
// Get the current value
console.log(otpInput.getValue()) // "123456"
// Set a value programmatically
otpInput.setValue('654321')
// Clear the value
otpInput.clear()
事件
| 事件 | 描述 |
|---|---|
complete.bs.otpInput | 当每个槽位都填满时触发。事件的value属性包含完整代码。 |
input.bs.otpInput | 每次更改时触发。事件的value属性包含当前值。 |
const otpElement = document.querySelector('.otp')
otpElement.addEventListener('complete.bs.otpInput', event => {
console.log('OTP complete:', event.value)
// Submit the form or validate the code
})
otpElement.addEventListener('input.bs.otpInput', event => {
console.log('Current value:', event.value)
})
无障碍访问
由于该控件是单个文本输入,它仅显示一个可访问名称、角色和值——因此辅助技术将其宣布为一个普通文本字段,而不是每个数字一个编辑字段。视觉槽是装饰性的,并标注为 aria-hidden,不需要每个数字的 aria-label。
- 为输入提供一个可访问的单一名称
aria-label或相关的<label>,并添加上下文aria-describedby. - 组件集合
autocomplete="one-time-code"以及适当的inputmode这样验证码可以自动填充,并且会显示正确的手机键盘。这支持 WCAG 1.3.5 识别输入目的. - 复制、粘贴和自动填充从不被阻止,这使得控件保持合规 WCAG 3.3.8 可访问的认证(最低要求)——单一输入也是密码管理器和短信自动填充可靠针对的对象。
- 对于验证流程本身,给验证码一个较长的有效期(WCAG 2.2.1 时间可调) 并避免强制用户在同一流程中重新输入已提供的代码 (WCAG 3.3.7 重复输入).
CSS
变量
OTP 输入在 .otp 上使用本地 CSS 变量进行实时自定义。CSS 变量的值是从每个组件独有的 Sass map生成,并应用于上述类。
// stylelint-disable custom-property-no-missing-var-function
// stylelint-disable-next-line scss/dollar-variable-default
$otp-tokens: defaults(
(
--otp-size: var(--btn-input-lg-min-height),
--otp-font-size: var(--btn-input-font-size),
--otp-gap: .5rem,
--otp-slot-fg: var(--btn-input-fg),
--otp-slot-bg: var(--btn-input-bg),
--otp-slot-border-width: var(--border-width),
--otp-slot-border-color: var(--border-color),
--otp-slot-border-radius: var(--radius-5),
),
$otp-tokens
);
Sass 列表
我们使用 Sass 列表来定义 OTP 输入的大小,因此你可以通过获取每个大小的关联根变量来轻松添加或修改大小。该列表通常应与中定义的大小相匹配 $form-control-sizes Sass map输入 _form-control.scss.
$otp-sizes: ();
// stylelint-disable-next-line scss/dollar-variable-default
$otp-sizes: defaults(
("sm", "lg"),
$otp-sizes
);