Form
组织字段、校验和提交过程。中文惯用名:表单。
稳定本期新增已接入
元信息
| 字段 | 值 |
|---|---|
| 规范 ID | component.form |
| 名称 | Form |
| 二级分类 | 数据录入(data-entry) |
| 用途 | 组织字段、校验和提交过程 |
| 描述 | 中文惯用名:表单。 |
预览
静态结构:Form 渲染为 data-slot="form" 的原生 <form>(layout="inline" 时叠加 flex flex-wrap items-center gap-3),经 React Context 下发 values / errors / setValue / registerField;子级表单控件(Input / Select / Textarea / NumberInput / Checkbox / RadioGroup / Switch / Slider / DatePicker / Calendar / Combobox)声明非空 name 即自动注册为表单项(label / rules 生效,值由 Form 托管)。提交按钮(Button submit:true)触发时统一校验已注册字段的 required 规则,失败渲染 data-slot="form-error" 并阻止提交;通过则把 values 写入 runtime state 的 form 路径(${form.<field>} 可用)并以 values 调用 onSubmit(Renderer 放入 event 作用域)。
DSL 结构
{
"type": "Form",
"events": {
"onSubmit": {
"action": "setState",
"params": {
"result": "${event}"
}
}
},
"children": [
{
"type": "Input",
"props": {
"name": "keyword",
"label": "关键词",
"placeholder": "输入关键词"
}
},
{
"type": "Select",
"props": {
"name": "status",
"label": "状态",
"placeholder": "选择状态",
"options": [
{
"label": "全部",
"value": "all"
},
{
"label": "进行中",
"value": "doing"
},
{
"label": "已完成",
"value": "done"
}
]
}
},
{
"type": "Button",
"props": {
"text": "提交",
"variant": "primary",
"submit": true
}
}
]
}何时用
何时使用
- 把多个录入控件组织为一次提交:新增 / 编辑表单、筛选条件、设置面板。
- 需要统一校验与错误汇总:字段声明 rules,提交时集中校验并阻止非法提交。
- 需要表单联动:用 form.setValues 动作批量回填字段(如按模板快速填充)。
何时不用
- 只有一个输入项且无校验 / 提交流程:直接使用单个控件(Input / Select)+ 按钮,不必引入 Form。
- 纯展示或查询条件即时生效的场景:用条件控件直接触发查询,不必包一层提交语义。
- 需要复杂嵌套 / 动态增删数组字段的可视化表单设计:当前实现为扁平字段集合,复杂编排需业务侧组合。
变体
| 变体 | 视觉形态 | 适用场景 |
|---|---|---|
| vertical 竖向(缺省) | label 在上、控件在下逐行排布 | 常规新增 / 编辑表单 |
| horizontal 横向 | label 与控件同行(formItemClass 按布局切换) | 字段少、label 短的表单 |
| inline 行内 | flex 横排自动换行,控件同处一行 | 筛选栏、工具栏等紧凑录入区 |
| initialValues 初始值 | 创建时以 initialValues 初始化 values | 编辑回显(字段级 value 优先于 initialValues) |
| rules 校验 | 提交失败时错误文案展示在对应字段下方 | 必填 / 格式校验,阻止非法提交 |
| onValuesChange 联动 | 任一字段变化即回调(changed + 全量 values) | 字段间联动(如选择类型后动态调整提示) |
API 属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
name | string | 'default' | 表单名:form.setValues 联动动作按名寻址,同页多表单需区分命名 |
layout | `'horizontal' | 'vertical' | 'inline'` |
initialValues | Record<string, unknown> | — | 表单初始值(创建时生效;字段级 value 优先于 initialValues[name]) |
onSubmit | (values: Record<string, unknown>) => void | — | 提交事件(校验通过后触发),参数为表单 values(Renderer 绑定 events.onSubmit) |
onValuesChange | (changed: Record<string, unknown>, values: Record<string, unknown>) => void | — | 任一字段变化事件,传出本次变化字段与全量 values |
children | ReactNode | — | 表单内容:声明了 name 的表单控件自动成为表单项,可混排布局与其他组件 |
className / style | string / CSSProperties | — | 通用:根节点 class 合并 / 内联样式(挂 <form> 根节点) |
使用规范
- 子控件必须声明非空 name 才会注册为表单项;未声明 name 的控件不会进入 values,也不会参与校验。
- 初始值优先级:字段级 value > initialValues[name],且字段级初始值仅首次注册时写入,不会覆盖用户已输入内容。
- 校验当前支持 required + message:自定义文案写进 rule.message,未提供时回退 i18n 必填提示。
- 提交按钮必须是 Button 且 submit:true 才会触发表单提交;普通按钮的 onClick 不经过校验流程。
- 校验通过后 values 会写入 runtime state 的 form 路径(${form.<field>}),同时经 event 传入 onSubmit 作用域。
- 同页多个 Form 通过 name 区分(缺省 default);form.setValues 联动需按名指定目标表单。
正例
- ✓ 新增表单:各字段声明 name + rules,底部 Button submit 提交,校验失败错误展示在字段下方。
- ✓ 编辑回显:initialValues 传后端返回的对象,字段级 value 按需覆盖个别字段。
- ✓ 筛选栏:layout="inline" + Input / Select 混排,提交后以 values 驱动列表查询。
反例
- ✕ 子控件忘记声明 name,提交时 values 为空,拿不到任何输入。
- ✕ 用普通 Button 的 onClick 直接提交数据,绕过统一校验与错误提示。
- ✕ 把字段级 value 当作「外部动态同步」手段——它只在首次注册写入一次,后续外部变化不会回填。
Design Token 映射
不适用:组件 tokenRefs 为空:样式 Token 数据尚未接入,三层映射(Primitive → Semantic → Component)待样式 Token 接入后回填。