Skip to content

InputOTP 验证码输入 ​

基础与分组

默认 6 位纯数字。groups 按「每组位数」分组,组间显示分隔符;没有可见标签时写 aria-label。

<pt-input-otp aria-label="验证码"></pt-input-otp>
<pt-input-otp groups="3-3" value="123" aria-label="分组验证码"></pt-input-otp>

一排定长的格子,每格一个字符,用于短信 / 邮件 / 两步验证的一次性验证码。

格子只是画出来的,真正接收输入的是盖在格子上的一个透明原生 <input>。所以这些都是原生的: iOS / Android 从短信里自动填充验证码(默认 autocomplete="one-time-code")、粘贴、撤销、输入法; 读屏器看到的也是一个普通的文本框,而不是六个无名的小输入框。

位数与字符规则 ​

位数与字符规则

length 决定位数;pattern 是单个字符要满足的正则,能收数字以外的字符时移动端弹全键盘。不合规则的字符键入时直接吞掉,粘贴时只过滤掉它们。

<pt-input-otp length="4" aria-label="4 位验证码"></pt-input-otp>
<pt-input-otp pattern="[0-9A-Za-z]" groups="4-4" length="8" aria-label="恢复码"></pt-input-otp>
  • length 是位数,默认 6。
  • pattern 是单个字符要满足的正则(写源码字符串,不带 ^ $),默认 [0-9]。写成 [0-9] / \d(或 [\d]、[0123456789])时移动端弹数字键盘,其余写法一律弹全键盘 —— 组件无法从任意正则证明它只收数字,宁可多给键也不能让键盘上缺了规则允许的字。
  • 键入不合规则的字符:直接吞掉,值不变。
  • 粘贴:只过滤掉不合规则的字符再填入,123-456 得到 123456;超出位数的截断。
  • 程序赋的 value 同样按规则过滤、截断(不发事件)。
  • 输入、粘贴、程序赋值都先做 NFKC 归一:输入法打出的全角数字 123 按 123 算。
  • 每格只收占一个 UTF-16 码元的字符:emoji 这类字符不论 pattern 怎么写都不收(原生 input 的长度与选区按码元计,收进来会切坏值)。
  • 输入法组合中(拼音、假名还没上屏)不过滤、不发事件,上屏后再统一处理。

编辑方式 ​

  • 聚焦时高亮下一个待填的格子;已填满时高亮最后一格。
  • 输入覆盖当前格,然后跳到下一格。
  • ← / → 一次移一格,Home / End 到两端;不能越过第一个空格子。
  • Backspace 删当前格,当前格是空的就删前一格;Delete 删当前格,后面的往前补。
  • 点哪格就编辑哪格。

格子顺序固定从左到右,RTL 页面里也一样:验证码是一串字符,不随书写方向排列。

事件 ​

事件何时触发
ptChange用户每改一次值(受控值的出口,v-model / ngModel 绑在它上面)
ptComplete值从不满到刚好填满 length 位的那一下;已满时改其中一格不重复触发

常见写法是在 ptComplete 里自动提交。按 Enter 会提交所属表单,与原生单行输入框一致, 外层对这次 Enter preventDefault() 可以取消。

尺寸与状态 ​

尺寸与状态

三档尺寸与其它控件同刻度(格子高 24 / 32 / 40)。出错态同时标注 aria-invalid。

<pt-input-otp size="sm" length="4" aria-label="小"></pt-input-otp>
<pt-input-otp size="lg" length="4" aria-label="大"></pt-input-otp>
<pt-input-otp invalid length="4" value="12" aria-label="出错"></pt-input-otp>
<pt-input-otp disabled length="4" value="1234" aria-label="禁用"></pt-input-otp>

表单 ​

  • 表单里提交的是 value 字符串,字段名取 name。
  • required 且为空:校验报「必填」。
  • 填了但不满 length 位:不论是否必填,校验都报「请输入完整的 N 位验证码」(tooShort)。
  • invalid 优先于「不满位数」,报自定义错误;空值且必填时仍报「必填」—— 与其它表单控件相同的优先级(必填 > 出错态 > 其余)。
  • reset() 回到初值。放进 pt-field / pt-field-set 时继承它们的禁用、必填与出错态。

无障碍 ​

  • 没有可见标签时写 aria-label(包装层里是 ariaLabelText),它落在内部的原生 input 上;放进 pt-field 时自动关联。
  • 格子与分隔符对读屏隐藏,读屏器读的是 input 里的完整值。
  • invalid 同时标注 aria-invalid,不只靠颜色。

已知限制 ​

密码管理器(1Password、LastPass 等)有时会往输入框末端插一个图标,可能盖住最后一格的一部分;组件不做避让。 需要时按各密码管理器自己的约定关掉它(如 1Password 认宿主上的 data-1p-ignore)。

API ​

属性

属性Attribute类型默认值说明
ariaLabelTextaria-labelstring | undefined—无障碍名称:原生 HTML 里写 aria-label,React / Vue / Angular 包装层里属性名是 ariaLabelText。 没有可见 label 时必须给。
autocompleteautocompletestring'one-time-code'透传给原生 input 的 autocomplete。默认 `one-time-code`:iOS / Android 据此从短信里取验证码
disableddisabledbooleanfalse禁用。只反映使用方自己写的值:外层原生 `<fieldset disabled>`、pt-field / pt-field-set 的禁用另经继承通道生效,不改写它
groupsgroupsstring | undefined—分组,写成用 `-` 连接的各组位数,如 `"3-3"`;组与组之间显示分隔符。 各组之和与 `length` 不符时忽略(控制台警告),按一组显示
inheritedDisabledinherited-disabledbooleanfalse外层 pt-field / pt-field-set 下发的禁用。内部继承通道:由它们以 attribute 维护,不建议使用方直接写。 有效禁用是 `disabled` 与它的并集
inheritedInvalidinherited-invalidbooleanfalse外层 pt-field 下发的出错态。内部继承通道:由 pt-field 维护,不建议使用方直接写。有效出错是 `invalid` 与它的并集
inheritedRequiredinherited-requiredbooleanfalse外层 pt-field 下发的必填。内部继承通道:由 pt-field 维护,不建议使用方直接写。有效必填是 `required` 与它的并集
invalidinvalidbooleanfalse出错态。校验信息由使用方展示,组件只负责视觉、aria-invalid 与表单校验状态(customError)
lengthlengthnumber6位数
namenamestring | undefined—提交表单时的字段名
patternpatternstring'[0-9]'**单个字符**要满足的正则(源码字符串,不写 `^` `$`)。默认只收数字。写成 `[0-9]` / `\d`(或 `[\d]`、 `[0123456789]`)时移动端弹数字键盘,其余写法一律弹全键盘。字母数字写 `"[0-9A-Za-z]"`。 输入先做 NFKC 归一(全角 `1` 按 `1` 算);emoji 这类占两个 UTF-16 码元的字符不论 pattern 都不收
readonlyreadonlybooleanfalse只读:能聚焦、能移动高亮格,不能改。值照常随表单提交
requiredrequiredbooleanfalse必填:值为空时表单校验报 valueMissing,并标注 aria-required
sizesize"lg" | "md" | "sm"'md'尺寸档位。格子高度对应 24 / 32 / 40 的控件刻度
valuevaluestring''当前值。程序赋的值同样按 `pattern` 与 `length` 过滤

事件

事件detail 类型说明
ptBlurvoid内部控件失去焦点
ptChangestring值变化。用户每改一次就触发一次,程序赋值不触发
ptCompletestring用户把值填满 `length` 位的那一下触发,detail 是完整的值。已满时再改其中一格不会重复触发
ptFocusvoid内部控件获得焦点

方法

方法说明
setFocus(options?: FocusOptions) => Promise<void>聚焦到内部 input,并高亮下一个待填的格子

可定制的内部元素(::part())

part说明
caret空格子上的假光标
group一组格子
input盖在格子上的透明原生 input
separator组与组之间的分隔符
slot单个格子
slot-active当前高亮的格子(与 slot 同一元素)

CSS 变量

变量说明
--pt-input-otp-radius每组两端的圆角,默认 --pt-radius-md(sm 档为 --pt-radius-sm)
--pt-input-otp-slot-width格子宽度,默认按「格子高 + 4px」的比例随高度走(默认档 28 / 36 / 44px)

Apache-2.0 协议开源