生态产品多个设计器现已发布候选版本

查看生态总览
跳转到内容

Fieldset 字段集 ​

把若干相关字段收成一组,组标题由 legend 提供,禁用与无效沿这一组下发。

根节点是原生 <fieldset>:整组禁用只需写一个属性,浏览器会停用组内所有表单控件。这是本组件存在的理由,换成 <div> 只剩一层灰色样式。

用法 ​

一组字段收进原生 fieldset:legend 是该组的名字,说明文案自动派生 id 并接入 aria-describedby

通知方式

至少保留一种,重要变更会照此通知你

组件结构 ​

加粗的是必需部件。

data-scope="fieldset":root · legend · description · field-group · actions · error-text

示例 ​

整组禁用 ​

disabled 写为原生 fieldset[disabled],组内每个控件一并禁用,不必逐个写 disabled

发票抬头

锁定期间这两个输入框既不能聚焦,也不参与提交

无效态 ​

invalid 切换后,错误文案接入描述链并显示;它带 role=alert,切换时读屏立即播报

联系方式

两者填一个即可

请至少填写一种联系方式

必填标记 ​

required 写为 data-required,皮肤据此为组标题加星号;星号只是视觉冗余,必填这一信息要一并写进文案

配送时段

必选一项,下单后不可更改

总开关放进 legend ​

按 HTML 规范,首个 legend 中的控件不受 fieldset[disabled] 连带影响,总开关因此始终可点击

备份频率

关掉总开关,下面两项跟着停用,唯独总开关自己还能点

设计指引 ​

何时使用 ​

  • 表单中有几段主题相同的字段(收货信息、发票抬头、通知偏好),需要一个组标题。
  • 需要一次禁用一整段字段,而不是逐个控件写 disabled。
  • 一组单选或复选选项需要共用一个问句作为组名。

何时不用 ​

  • 只有一个控件加一个标签时,使用表单字段;字段负责单个控件,字段集负责一组。
  • 需要整表的值管理与校验时,外层使用表单,字段集只负责分组。
  • 只在视觉上分段、没有共同的组名与禁用语义时,使用分隔线或卡片。

特性 ​

  • disabled 落为原生 fieldset[disabled],同时作为作用域配置压进子树:组内组件库的控件各自拿到 disabled,不可聚焦、不可编辑、不参与提交,禁用面也一起到位,不需要逐个控件接线。组内的字段同样拿到 disabled,标题与说明随控件一起变淡。
  • 说明文字与错误文案自动派生 id 并接入根节点的 aria-describedby,作者不需要写 id。描述链只引用实际渲染了的部件:没写说明、或说明读不出一句话(没有文字,或只有对读屏隐藏的内容,判断同 hasNamingContent)时不留 id,引用不会落空;说明后补上内容时跟着接上。
  • 错误文案带 role="status" + aria-live="polite",节点常驻、通过 hidden 显隐,invalid 翻转时读屏排队播报,不打断当前朗读。整表提交失败时的打断式播报只由 Form 的错误摘要发出。
  • invalid 落为根与组标题上的 data-invalid,组标题据此转为警示色,同时把错误文案接入描述链并显示。
  • required 落为根与组标题上的 data-required,组标题的星号由 label 公共层按组标题自己的这一位画。
  • field-group 把并排的几个字段圈成一段(宽度足够时自动分栏),actions 承载组末尾的按钮行。
  • 不写结构时按标准结构铺(Vue 不写默认插槽、React 不给 children、Web Components 不写部件或只写 root),三端出自同一个结构函数:组标题恒铺在最前,文字取 legend;说明、字段区、错误文案、按钮行给了内容才铺,依次排在后面。Vue 是 legend、description、fieldGroup、errorText、actions 具名插槽,React 是同名属性,Web Components 是宿主直接子节点上的 slot="legend"、slot="description"、slot="field-group"、slot="error-text"、slot="actions"。
  • 作用域禁用只落在组件库的控件上;作者自己写的 div 型交互节点不在原生 fieldset[disabled] 的管辖内,需要各自接 disabled。
  • 滚动条不受连坐:组内的滚动区照常可以滚动、拖动,选择器列表里内嵌的滚动条也不随选择器禁用;要停用滚动条,在它自己身上写 disabled。

组合 ​

  • 内部按顺序放若干表单字段,每个字段自行管理标签与错误文案。
  • 一组单选放单选组、一组多选放复选框组。这两个组仍要写自己的 label 部件:字段集的标题命名的是外层这一段,内层的组需要自己的名称,legend 不会向下传递。
  • 外层放表单统一收集值与校验,字段集只承担分组与整段禁用。

最佳实践 ​

  • 组标题写成可读通的名词短语或问句(“通知方式”而不是“选项”),读屏进组时读的就是它。
  • 整段停用优先写在字段集上,不逐个控件写 disabled,避免遗漏。
  • 错误文案说明整组哪里不满足(“至少填写一种联系方式”),单个字段的错误留给该字段。

反模式 ​

  • 用 <div> 替代字段集:禁用不再联动,读屏也无法识别为一组。
  • 把 <legend> 移到中间或包一层容器:它不是首个子节点时就不再是组名。
  • 只用一条分割线和一行加粗文字表示分组:视觉上像一组,无障碍树中仍是分散的。
  • 一个字段集内放入多个互不相关的主题,标题只能写成“其他”。
  • 开启 invalid 却不渲染错误文案:屏幕上只有组标题变色,读屏用户无法得知这一组有问题。

API 参考 ​

产物 ​

层值
自定义元素<xh-fieldset>
Vue 组件XhFieldsetActions XhFieldsetDescription XhFieldsetErrorText XhFieldsetFieldGroup XhFieldsetLegend XhFieldsetRoot
组合式函数useFieldset
状态机无,connect 直接由 props 算属性
皮肤@xihan-ui/styles/fieldset.css

Props ​

属性类型必填说明
disabledboolean整组禁用。root 是原生 &lt;fieldset&gt;,该条落为原生 disabled 属性, 浏览器会把组内每个表单控件一并禁用(首个 &lt;legend&gt; 中的控件按 HTML 规范除外)。
invalidboolean校验失败态:root 上写 data-invalid,错误文案接入描述链并显示。
partsFieldsetRenderedParts作者实际渲染了哪些部件,由适配器统计;省略即按都在场处理(服务端直出与挂载前)。 不在场的部件不进 root 的描述链:指向不存在的 id 会被判为无效引用。 description 渲染了但读不出一句话(判断同 hasNamingContent)也按不在场处理。
requiredboolean必填标记:落为 data-required,供皮肤给组标题加星号,校验仍由宿主负责。 不产出 aria-required:该属性在 group 角色上不受支持,写入也不进入无障碍树。
translationsPartial<FieldsetTranslations>文案覆盖。本组件当前没有外露文案,保留该位,接全局配置的通道由适配器铺设。

插槽 ​

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhFieldsetRootdefault—
XhFieldsetRootlegend—
XhFieldsetRootdescription—
XhFieldsetRootfieldGroup—
XhFieldsetRooterrorText—
XhFieldsetRootactions—

React 适配器 props ​

只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。

React 组件属性类型必填说明
XhFieldsetRootlegendReactNode组标题。不给 children 时铺 legend 部件。
XhFieldsetRootdescriptionReactNode组标题下的说明。不给 children 时铺 description 部件。
XhFieldsetRootfieldGroupReactNode组里的字段。不给 children 时铺进 field-group 部件:宽度够时并排分栏,只放一个容器时它占满整行。
XhFieldsetRooterrorTextReactNode错误文案。不给 children 时铺 error-text 部件,invalid 时显示。
XhFieldsetRootactionsReactNode组末尾的按钮行。不给 children 时铺 actions 部件。
XhFieldsetRootchildrenReactNode

connect API ​

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
disabledboolean
invalidboolean
requiredboolean
getRootProps() => T['element']
getLegendProps() => T['element']
getDescriptionProps() => T['element']
getFieldGroupProps() => T['element']把并排的几个字段划为一段;纯排版,不承担分组语义(组名与描述归 root)。
getActionsProps() => T['element']组末尾的按钮行;纯排版。
getErrorTextProps() => T['element']

无障碍 ​

键盘 ​

规格出处:W3C APG

无键盘交互(不接收焦点,或焦点行为完全由原生元素提供)。

ARIA ​

以下属性由 connect 生成。

部件属性值
rootaria-describedby[ props.parts?.description !== false ? ids.descriptio…
error-textaria-atomic'true'
error-textaria-live'polite'
error-textrole'status'
  • 组名来自原生 <legend>,它必须是 <fieldset> 的首个子节点,否则浏览器不将其视为组名。
  • 组标题不另发 aria-labelledby:多一份名称来源会与原生名称叠加,读屏会读两遍。
  • 根节点不产出 aria-invalid / aria-required:这两个属性在 group 角色上不受支持,写了也不进入无障碍树;无效与必填的读屏出口是错误文案与描述链。
  • 只要 invalid 可能为真,就必须渲染错误文案部件。它是该状态唯一的读屏出口:组标题变色只是视觉提示,无障碍树不会变化。
  • 必填要写进组标题的可见文字或说明文案(“通知方式(必填)”“以下三项至少填一项”)。皮肤的星号是 CSS 生成内容,用户自定义样式表关闭 content 或读屏不朗读生成内容时它不存在,只能作为视觉冗余。
  • 按 HTML 规范,首个 <legend> 内的控件不受 fieldset[disabled] 影响。需要让某个开关在整组停用时仍可操作(例如“启用本段”的总开关),把它放进 <legend>。

样式参考 ​

皮肤 ​

@xihan-ui/styles/fieldset.css 按 [data-scope="fieldset"][data-part="root"] 部件选择器书写,发布产物以挂载类 .xh-scope-fieldset 代替其中的 data-scope(特异性相同),位于 xihan.components 层。覆盖样式使用 xihan.overrides,部件选择器照常可用。

数据属性 ​

由 connect 生成;条件不成立时不输出无值属性。

部件属性值
rootdata-disabled''(条件成立时才出现)
rootdata-invalid''(条件成立时才出现)
rootdata-required''(条件成立时才出现)
legenddata-disabled''(条件成立时才出现)
legenddata-invalid''(条件成立时才出现)
legenddata-required''(条件成立时才出现)
descriptiondata-disabled''(条件成立时才出现)
field-groupdata-disabled''(条件成立时才出现)
actionsdata-disabled''(条件成立时才出现)

CSS 变量 ​

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-fieldset-actions-gapactionsgapdefault--xh-space-2fieldset 的 actions 部件 gap 覆盖槽。
--xh-fieldset-description-fgdescriptioncolordefault--xh-fg-subtlefieldset 的 description 部件 color 覆盖槽。
--xh-fieldset-description-fg-disableddescriptioncolordisabled--xh-fg-subtlefieldset 的 description 部件 color 覆盖槽。
--xh-fieldset-description-font-sizedescriptionfont-sizedefault--xh-text-caption-sizefieldset 的 description 部件 font-size 覆盖槽。
--xh-fieldset-error-fgerror-textcolordefault--xh-fg-dangerfieldset 的 error-text 部件 color 覆盖槽。
--xh-fieldset-error-font-sizeerror-textfont-sizedefault--xh-text-caption-sizefieldset 的 error-text 部件 font-size 覆盖槽。
--xh-fieldset-field-group-col-wfield-groupgrid-template-columnsdefault--xh-layout-col-min-smfieldset 的 field-group 部件 grid-template-columns 覆盖槽。
--xh-fieldset-field-group-gapfield-groupgapdefault--xh-space-3fieldset 的 field-group 部件 gap 覆盖槽。
--xh-fieldset-gaprootmargin-block-endwhere(:not(:last-child)
where([data-scope='fieldset'][data-part='root'])
--xh-space-5fieldset 的 root 部件 margin-block-end 覆盖槽。
--xh-fieldset-legend-fglegendcolordefault--xh-fg-defaultfieldset 的 legend 部件 color 覆盖槽。
--xh-fieldset-legend-fg-disabledlegend
root
colordisabled--xh-fg-subtlefieldset 的 legend、root 部件 color 覆盖槽。
--xh-fieldset-legend-fg-invalidlegendcolorinvalid--xh-fg-dangerfieldset 的 legend 部件 color 覆盖槽。
--xh-fieldset-legend-font-sizelegendfont-sizedefault--xh-text-heading-3-sizefieldset 的 legend 部件 font-size 覆盖槽。
--xh-fieldset-legend-font-weightlegendfont-weightdefault--xh-text-heading-3-weightfieldset 的 legend 部件 font-weight 覆盖槽。
--xh-fieldset-legend-gaplegendmargin-block-enddefault--xh-space-4fieldset 的 legend 部件 margin-block-end 覆盖槽。
--xh-fieldset-legend-starlegendcolorrequired--xh-fg-dangerfieldset 的 legend 部件 color 覆盖槽。

动效 ​

动效角色:状态(见动效规范)。

color 走 transition 过渡。时长与缓动读动效令牌,改令牌即改全局节奏。

系统开启减弱动效时由令牌层统一收敛,皮肤不另作判断。

Released under The MIT License