一个 React 表单,采用 Liquid Glass 布局,提供统一的错误处理与表单级校验。
Form 渲染原生 <form>,并统一协调内部字段的校验与外部错误。它提供表单上下文,让每个 Field 无需单独维护状态就能显示错误。
当多个字段共享同一次提交与错误状态时使用 Form。单个控件请使用 Field;需要把相关字段组织在同一个标题下时,使用 Fieldset。
把字段与操作作为 children 传入。Form 使用共享间距提供纵向布局,因此通常只需要通过 className 设置宽度。原生 <form> 元素保留浏览器提交、FormData 与服务端 action 的能力。
把 errors 设置为以每个 Field 的 name 为 key 的对象。字符串渲染一条信息;数组会渲染其中的每条信息,两条及以上会包裹为列表。Field 会通过 aria-describedby 把信息关联到控件并标记为无效;用户编辑该字段时,Base UI 会清除对应条目。
Field 自身的 error 属性优先于 Form.errors 中的同名条目。只有通过 Field 渲染的字段会读取错误表;自带标签的控件,例如 Checkbox、Select 与 CheckboxGroup,只有在包裹于具有匹配 name 的 Field 中时才会显示表单错误,否则请对这类控件使用原生约束校验,或在控件旁渲染提示信息。
validationMode 设置表单内所有字段的默认校验时机:
onSubmit(默认)在提交时校验,之后每次变更都会重新校验。onBlur 在字段失焦时校验。onChange 在每次变更时校验。Field 上的 validationMode 属性优先。提交失败后,表单会把焦点移到第一个无效控件,并阻止提交事件。
使用 actionsRef 按需校验。调用 actionsRef.current?.validate() 会校验全部字段;传入名称则只校验一个字段。
const actionsRef = React.useRef<{
validate: (fieldName?: string) => void;
} | null>(null);
<Form actionsRef={actionsRef}>{/* fields */}</Form>;
actionsRef.current?.validate();
actionsRef.current?.validate("email");使用 onFormSubmit 可以直接获得 JavaScript 对象,而不是 FormData 实例。值来自通过 Field 注册的字段,并以它们的 name 为 key。原生提交事件会被自动阻止。
由于对象来自 Field 注册,通过自身 hidden input 提交的控件(例如 Checkbox、Select、Slider、Switch、RadioGroup 与 CheckboxGroup)只有在包裹于 Field 中并以 name 注册时才会包含在内。若它们在 Field 之外使用,且一次提交同时包含这两类控件,请在原生 onSubmit 中从 FormData 读取这些值。
Form 渲染原生 <form> 元素,但不会自动添加可访问名称;当页面包含多个表单时,请使用 aria-label 或 aria-labelledby。单个控件的标签来自 Field,提交按钮保留自己的可访问名称。
原生表单行为保持不变:存在提交按钮时,在文本框中按 Enter 会提交,自动填充与 FormData 也能继续使用。Base UI 会关闭浏览器的原生校验气泡,改由 Field 完成校验。提交失败后,焦点会移到第一个无效控件,让键盘与屏幕阅读器用户直接到达问题位置。表单级错误通过控件的 aria-describedby 关系播报。表单模式见可访问性指南。
Form
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
children | ReactNode | — | 表单内的字段与操作。 |
errors | Record<string, string | string[]> | — | 按 Field 的 name 组织的外部错误。字符串渲染一条信息;数组会渲染其中的每条信息,两条及以上会包裹为列表。 |
onFormSubmit | (formValues: Record<string, any>, eventDetails: { reason: "none"; event: Event }) => void | — | 接收通过 Field 注册的控件值,并阻止原生提交事件。 |
validationMode | "onSubmit" | "onBlur" | "onChange" | "onSubmit" | 表单内字段的默认校验时机。Field 上的属性优先。 |
actionsRef | RefObject<{ validate: (fieldName?: string) => void } | null> | — | 主动校验全部字段,或按名称校验单个字段。 |
className | string | — | 合并到 form 元素的 Tailwind 类。 |
style | CSSProperties | — | 内联样式,合并到与 className 相同的元素。 |
ui | { root?: ClassValue } | — | 按 data-slot 覆盖 root 槽位的 Tailwind 类。 |
render | ReactElement | ((props, state) => ReactElement) | — | 替换表单根元素。 |
其余 Base UI Form 属性与原生 <form> 属性会透传,包括 action、method、onSubmit、id 与 aria-*。
| 属性 | 说明 |
|---|---|
data-slot | 标记表单根元素(root),用于样式覆盖。 |
Form 本身不提供额外状态 data-* 属性。
Form 本身没有玻璃表面,会继承页面材质。它的根元素使用纵向堆叠与 gap-4 节奏,并使用共享的 --ui-ink 文字颜色。可以通过 className 覆盖布局,并通过 ui.root 按 data-slot 覆盖表单根元素。Token 分层与预设见主题指南。