Components

一次性密码字段

一组单字符文本输入,用于处理一次性密码验证。

import * as React from "react";
import { unstable_OneTimePasswordField as OneTimePasswordField } from "radix-ui";
const OneTimePasswordFieldDemo = () => (
<OneTimePasswordField.Root className="OTPRoot">
<OneTimePasswordField.Input className="OTPInput" />
<OneTimePasswordField.Input className="OTPInput" />
<OneTimePasswordField.Input className="OTPInput" />
<OneTimePasswordField.Input className="OTPInput" />
<OneTimePasswordField.Input className="OTPInput" />
<OneTimePasswordField.Input className="OTPInput" />
<OneTimePasswordField.HiddenInput />
</OneTimePasswordField.Root>
);
export default OneTimePasswordFieldDemo;

Features

    模仿单个输入字段的键盘导航

    粘贴时覆盖值

    密码管理器自动填充支持

    对数字和字母数字值的输入验证

    完成后自动提交

    隐藏输入以为表单数据提供单个值

结构

导入所有部分并将其组合在一起。

import { unstable_OneTimePasswordField as OneTimePasswordField } from "radix-ui";
export default () => (
<OneTimePasswordField.Root>
{/* 每个字符一个输入 */}
<OneTimePasswordField.Input />
{/* 单个隐藏输入用于存储完整值 */}
<OneTimePasswordField.HiddenInput />
</OneTimePasswordField.Root>
);

API 参考

Root

包含一次性密码字段的所有部分。

PropTypeDefault
asChild
boolean
false
autoComplete
enum
one-time-code
autoFocus
boolean
No default value
value
string
No default value
defaultValue
string
No default value
onValueChange
function
No default value
autoSubmit
boolean
false
onAutoSubmit
function
No default value
disabled
boolean
false
dir
enum
"ltr"
orientation
enum
"vertical"
form
string
No default value
name
string
No default value
placeholder
string
No default value
readOnly
boolean
false
sanitizeValue
function
No default value
type
enum
"text"
validationType
enum
"numeric"
Data attributeValues
[data-orientation]"vertical" | "horizontal"

Input

呈现一个文本输入,表示值中的单个字符。

PropTypeDefault
asChild
boolean
false
Data attributeValues
[data-index]

与根字段值相对的字符索引对应的索引

HiddenInput

PropTypeDefault
asChild
boolean
false

示例

基本用法

// 这将呈现一个包含 6 个输入的字段,用于 6 个字符的密码。
// 为每个字符的密码长度渲染一个 Input 组件。
<OneTimePasswordField.Root>
<OneTimePasswordField.Input />
<OneTimePasswordField.Input />
<OneTimePasswordField.Input />
<OneTimePasswordField.Input />
<OneTimePasswordField.Input />
<OneTimePasswordField.Input />
<OneTimePasswordField.HiddenInput />
</OneTimePasswordField.Root>

分段控件

Root 组件接受任意子项,因此在输入之间渲染视觉分隔列表就像在输入之间渲染分隔符一样简单。我们建议使用 aria-hidden 隐藏装饰元素,以防辅助技术,并避免在 Root 中渲染其他有意义的内容,因为每个子元素预计都属于具有 group 角色的父元素。

<OneTimePasswordField.Root>
<OneTimePasswordField.Input />
<Separator.Root aria-hidden />
<OneTimePasswordField.Input />
<Separator.Root aria-hidden />
<OneTimePasswordField.Input />
<Separator.Root aria-hidden />
<OneTimePasswordField.Input />
<OneTimePasswordField.HiddenInput />
</OneTimePasswordField.Root>

输入密码时自动提交表单

使用 autoSubmit 属性,当所有输入都被填写时提交关联的表单。

function Verify({ validCode }) {
const PASSWORD_LENGTH = 6;
function handleSubmit(event) {
event.preventDefault();
const formData = event.formData;
if (formData.get("otp") === validCode) {
redirect("/authenticated");
} else {
window.alert("无效的代码");
}
}
return (
<form onSubmit={handleSubmit}>
<OneTimePasswordField.Root name="otp" autoSubmit>
{PASSWORD_LENGTH.map((_, i) => (
<OneTimePasswordField.Input key={i} />
))}
{/* HiddenInput 是必需的,以便表单具有与字段相关联的数据 */}
<OneTimePasswordField.HiddenInput />
</OneTimePasswordField.Root>
<button>提交</button>
</form>
);
}

受控值

function Verify({ validCode }) {
const [value, setValue] = React.useState("");
const PASSWORD_LENGTH = 6;
function handleSubmit() {
if (value === validCode) {
redirect("/authenticated");
} else {
window.alert("无效的代码");
}
}
return (
<OneTimePasswordField.Root autoSubmit value={value} onAutoSubmit={handleSubmit} onValueChange={setValue} >
{PASSWORD_LENGTH.map((_, i) => (
<OneTimePasswordField.Input key={i} />
))}
</OneTimePasswordField.Root>
);
}

可访问性

撰写本文时,WCAG 指南中没有实施一次性密码字段作为单独输入的单一确定的模式。该行为旨在尽可能接近使字段像单个输入一样运行,并根据我们最初的研究、测试和反馈收集进行了一些例外。

此组件作为具有 group 角色的容器内的 input 元素实现,以指示子输入相关联。可以使用方向键进行导航和聚焦,键入输入将移动焦点到下一个输入,直到到达最后一个输入。

将值粘贴到字段中将替换所有输入的内容,无论当前聚焦的输入是什么。根据我们的研究,这似乎与大多数用户期望相符,因为值通常是从密码管理器或电子邮件中粘贴过来的。

键盘交互

KeyDescription
Enter
如果找到关联的 form,将尝试提交
Tab
将焦点移动到 Root 外部的下一个可聚焦元素
Shift + Tab
将焦点移动到 Root 外部的前一个可聚焦元素
ArrowDown
orientationvertical 时,将焦点移动到下一个 Input
ArrowUp
orientationvertical 时,将焦点移动到前一个 Input
ArrowRight
orientationhorizontal 时,将焦点移动到下一个 Input
ArrowLeft
orientationhorizontal 时,将焦点移动到前一个 Input
Home
将焦点移动到第一个 Input
End
将焦点移动到最后一个 Input
Delete
删除当前聚焦的 Input 中的字符,并将以后的值向后移动
Backspace
删除当前聚焦的 Input 中的字符,并将焦点移动到前一个 Input
Command + Backspace
清除所有 Input 元素的值