Checkbox 复选框
用于选择一个或多个独立选项。
用法
标记一个独立选项
组件结构
加粗的是必需部件。
data-scope="checkbox":root · indicator · hidden-input · label · text
示例
不确定状态
表示部分选中
颜色
tone 决定勾中后方框使用哪族颜色,因此这里都设为勾中
尺寸
适配不同的界面密度
禁用与只读
区分不可用与不可修改状态
校验状态
标记必须处理的选项
设计指引
何时使用
- 表单中的同意、订阅或启用选项。
- 需要表达部分选中的汇总状态。
何时不用
特性
- 支持选中、未选中与
indeterminate状态。 - 方框是字段家族的控制盒:不填底、描边与无影,勾中后以语气色填充,按下缩放并换底。
readOnly仍可聚焦并参与提交,disabled不参与提交。- 标签、三档尺寸、校验状态和自定义指示器均使用同一状态动画。
name与value通过隐藏字段参与原生表单。
组合
- 将文字直接放入默认插槽,整行即可点击。
- 成组选择使用复选框组。
最佳实践
- 始终提供可见标签或
aria-label。 - 半选只用于表示下级选项的汇总状态。
反模式
- 不要用复选框表达互斥选项。
- 不要将半选状态作为第三个业务值。
API 参考
产物
| 层 | 值 |
|---|---|
| 自定义元素 | <xh-checkbox> |
| Vue 组件 | XhCheckbox |
| 组合式函数 | useCheckbox |
| 状态机 | checkboxMachine |
| 皮肤 | @xihan-ui/styles/checkbox.css |
Props
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
checked | CheckboxCheckedState | ||
defaultChecked | CheckboxCheckedState | ||
disabled | boolean | ||
readOnly | boolean | 只读:不可勾选,但仍可聚焦、仍参与提交,对比度不降低。 | |
invalid | boolean | 校验失败:只改变呈现,不阻止交互。 | |
required | boolean | 必填:随表单校验一起使用,只发无障碍属性,不自行拦截提交。 | |
name | string | 表单字段名;提供后 hidden-input 才带 name 并参与提交。 | |
value | string | 提交的值,默认 'on',与原生复选框一致。 | |
tone | Tone | 语气:brand / neutral / success / warning / danger / info,决定选中态使用哪族颜色。 | |
size | Size | 尺寸:sm / md / lg,决定方框边长与勾选符号的字号档位。 | |
onCheckedChange | (details: CheckboxCheckedChangeDetails) => void | checked 变化意图回调;受控时是唯一出口,非受控时随内部转移一并通知。 |
事件
自定义元素将载荷放在 detail;Vue 使用同名 emit。
| 事件 | 载荷 | 说明 |
|---|---|---|
checked-change | CheckboxCheckedChangeDetails | checked 状态变化;detail 为 { checked: boolean } |
插槽
仅列出带载荷的插槽。
| Vue 组件 | 插槽 | 载荷 | 说明 |
|---|---|---|---|
XhCheckbox | default | — | 方框旁的文字;未写时只有一个方框。 |
XhCheckbox | indicator | — | 方框中的图形;未写时由皮肤绘制勾选标记。 |
React 适配器 props
只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。
| React 组件 | 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
XhCheckbox | indicator | ReactNode | 方框中的图形;未写时由皮肤绘制勾选标记。 | |
XhCheckbox | children | ReactNode | 方框旁的文字;未写时只有一个方框。 |
状态
公开状态写入 data-state。
| 部件 | 取值 |
|---|---|
root | 'indeterminate' | 'checked' | 'unchecked' |
indicator | 'indeterminate' | 'checked' | 'unchecked' |
label | 'indeterminate' | 'checked' | 'unchecked' |
text | 'indeterminate' | 'checked' | 'unchecked' |
以下名称仅用于内部状态机。
状态:off · on · indeterminate
事件:TOGGLE · CHECK · UNCHECK · CONTROLLED.ON · CONTROLLED.OFF · CONTROLLED.INDETERMINATE · FORM.RESET · PRESS.START · PRESS.END
判据:isCheckedControlled · defaultsToChecked · defaultsToIndeterminate · canPress
connect API
getXxxProps() 返回对应部件的宿主属性。
| 成员 | 类型 | 说明 |
|---|---|---|
checked | CheckboxCheckedState | |
setChecked | (next: boolean) => void | 半选只能由 checked prop 给出,这里只接受全选 / 全不选。 |
getRootProps | () => T['button'] | |
getIndicatorProps | () => T['element'] | |
getHiddenInputProps | () => T['input'] | 表单影子:勾选后才提交,半选按未勾选处理。提供 name 后才带 name。 |
getLabelProps | () => T['label'] | 包裹方框与文字的 <label>:点击文字即切换,方框的可及名来自文字。只在带文字时渲染。 |
getTextProps | () => T['element'] | 方框旁的文字。 |
无障碍
键盘
规格出处:W3C APG
| 按键 | 生效条件 | 行为 |
|---|---|---|
Space / Enter | focus in root, not disabled | 切换 checked 状态 |
Space / Enter | held in root, not disabled, not readOnly | 按住期间投影 data-pressed,与指针 :active 同一副按压面;抬起或失焦撤下,按住途中转入禁用或只读也撤下。与勾选态互相独立 |
ARIA
以下属性由 connect 生成。
| 部件 | 属性 | 值 |
|---|---|---|
root | aria-checked | 'mixed' | 'true' | 'false' |
root | aria-invalid | 'true' | 'false' |
root | aria-readonly | 'true' | 'false' |
root | aria-required | 'true' | 'false' |
root | role | 'checkbox' |
indicator | aria-hidden | 'true' |
样式参考
皮肤
@xihan-ui/styles/checkbox.css 使用 [data-scope="checkbox"][data-part="root"] 部件选择器,位于 xihan.components 层。覆盖样式使用 xihan.overrides。
forced-colors: active 下另有一套规则:颜色交给系统,边框与状态标记改用系统色关键字。
数据属性
由 connect 生成;条件不成立时不输出无值属性。
| 部件 | 属性 | 值 |
|---|---|---|
root | data-disabled | ''(条件成立时才出现) |
root | data-invalid | ''(条件成立时才出现) |
root | data-pressed | ''(条件成立时才出现) |
root | data-readonly | ''(条件成立时才出现) |
root | data-required | ''(条件成立时才出现) |
root | data-size | props.size |
root | data-state | 'indeterminate' | 'checked' | 'unchecked' |
root | data-tone | props.tone |
root | data-xh-action-control | '' |
root | data-xh-action-display | 'always' |
root | data-xh-action-profile | 'icon' |
root | data-xh-action-size | props.size |
root | data-xh-action-variant | 'outline' |
indicator | data-state | 'indeterminate' | 'checked' | 'unchecked' |
label | data-disabled | ''(条件成立时才出现) |
label | data-invalid | ''(条件成立时才出现) |
label | data-readonly | ''(条件成立时才出现) |
label | data-size | props.size |
label | data-state | 'indeterminate' | 'checked' | 'unchecked' |
text | data-disabled | ''(条件成立时才出现) |
text | data-invalid | ''(条件成立时才出现) |
text | data-state | 'indeterminate' | 'checked' | 'unchecked' |
CSS 变量
本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。
| 变量 | 部件 | CSS 属性 | 状态 | 默认来源 | 说明 |
|---|---|---|---|---|---|
--xh-checkbox-bg | root | --xh-ink-surfacebackground-color | defaultdisabledfocus-visiblehoveris(:active, [data-pressed])loadingnot([data-disabled])not([data-loading])pressedreadonlyxh-ink-surface | transparent | checkbox 的 root 部件 --xh-ink-surface、background-color 覆盖槽。 |
--xh-checkbox-bg-checked | root | --xh-ink-surfacebackground-color | disabledfocus-visiblehoveris(:active, [data-pressed])loadingnot([data-disabled])not([data-loading])pressedreadonlystate=checkedstate=indeterminatexh-ink-surface | --xh-_checkbox-accent | checkbox 的 root 部件 --xh-ink-surface、background-color 覆盖槽。 |
--xh-checkbox-bg-checked-pressed | root | background-color | disabledis(:active, [data-pressed])loadingnot([data-disabled])not([data-loading])pressedstate=checkedstate=indeterminate | --xh-_tone-active | checkbox 的 root 部件 background-color 覆盖槽。 |
--xh-checkbox-bg-disabled | root | --xh-ink-surfacebackground-color | disabledxh-ink-surface | --xh-bg-subtle | checkbox 的 root 部件 --xh-ink-surface、background-color 覆盖槽。 |
--xh-checkbox-bg-pressed | root | background-color | disabledis(:active, [data-pressed])loadingnot([data-disabled])not([data-loading])pressed | --xh-bg-subtle-hover | checkbox 的 root 部件 background-color 覆盖槽。 |
--xh-checkbox-border | labelroot | borderborder-color | @media (hover: hover)contrast=moredefaultdisabledfocus-visiblehoveris(:active, [data-pressed])loadingnot([data-disabled])not([data-loading])not([data-readonly])pressedreadonlystate=uncheckedwhere([data-contrast='more']) | --xh-border-control--xh-border-strong | checkbox 的 label、root 部件 border、border-color 覆盖槽。 |
--xh-checkbox-border-checked | labelroot | borderborder-color | @media (hover: hover)disabledfocus-visiblehoveris(:active, [data-pressed])loadingnot([data-disabled])not([data-loading])not([data-readonly])pressedreadonlystate=checkedstate=indeterminate | --xh-_checkbox-accent | checkbox 的 label、root 部件 border、border-color 覆盖槽。 |
--xh-checkbox-border-disabled | root | border-color | disabled | --xh-border-default | checkbox 的 root 部件 border-color 覆盖槽。 |
--xh-checkbox-border-hover | labelroot | border-color | @media (hover: hover)disabledhoveris(:active, [data-pressed])loadingnot([data-disabled])not([data-loading])not([data-readonly])pressedreadonly | --xh-border-control-hover | checkbox 的 label、root 部件 border-color 覆盖槽。 |
--xh-checkbox-border-invalid | labelroot | borderborder-color | @media (hover: hover)disabledfocus-visiblehoverinvalidis(:active, [data-pressed])loadingnot([data-disabled])not([data-loading])not([data-readonly])pressedreadonlystate=checkedstate=indeterminate | --xh-border-invalid | checkbox 的 label、root 部件 border、border-color 覆盖槽。 |
--xh-checkbox-fg | root | color | defaultdisabledfocus-visiblehoveris(:active, [data-pressed])loadingnot([data-disabled])not([data-loading])pressed | --xh-_checkbox-on-accent | checkbox 的 root 部件 color 覆盖槽。 |
--xh-checkbox-fg-disabled | indicatorroot | background-colorcolor | disabledstate=indeterminate | --xh-fg-disabled | checkbox 的 indicator、root 部件 background-color、color 覆盖槽。 |
--xh-checkbox-fg-invalid | labeltext | color | invalid | --xh-fg-danger | checkbox 的 label、text 部件 color 覆盖槽。 |
--xh-checkbox-icon-size | root | --xh-icon-size | default | --xh-_checkbox-glyph | checkbox 的 root 部件 --xh-icon-size 覆盖槽。 |
--xh-checkbox-indicator-fg | indicator | background-color | state=indeterminate | --xh-_checkbox-on-accent | checkbox 的 indicator 部件 background-color 覆盖槽。 |
--xh-checkbox-label-fg | label | color | default | --xh-fg-default | checkbox 的 label 部件 color 覆盖槽。 |
--xh-checkbox-label-fg-disabled | label | color | disabled | --xh-fg-subtle | checkbox 的 label 部件 color 覆盖槽。 |
--xh-checkbox-label-font-size | label | font-size | default | --xh-_checkbox-label-font-size | checkbox 的 label 部件 font-size 覆盖槽。 |
--xh-checkbox-label-gap | label | gap | default | --xh-_checkbox-label-gap | checkbox 的 label 部件 gap 覆盖槽。 |
--xh-checkbox-label-leading | label | line-height | default | --xh-leading-normal | checkbox 的 label 部件 line-height 覆盖槽。 |
--xh-checkbox-radius | root | border-radius | default | --xh-shape-inset | checkbox 的 root 部件 border-radius 覆盖槽。 |
--xh-checkbox-shadow | root | box-shadow | defaultdisabledfocus-visiblehoveris(:active, [data-pressed])loadingnot([data-disabled])not([data-loading])pressed | none | checkbox 的 root 部件 box-shadow 覆盖槽。 |
动效
动效角色:按压 · 状态 · 切换(见动效规范)。
opacity · scale 走 transition 过渡。时长与缓动读动效令牌,改令牌即改全局节奏。
系统开启减弱动效时由令牌层统一收敛,皮肤不另作判断。
响应式
皮肤另按输入能力分档:hover: hover · pointer: coarse:同一份皮肤在触屏与带指针的设备上不一样,与视口宽度无关。
RTL
皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像。
