跳转到内容

RadioGroup 单选组 ​

一组互斥选项共用一个值,所有选项同时可见。单个单选按钮是这里的 item 部件,不另立组件:它脱离组既没有互斥对象,也无法取消选中。

用法 ​

组内只有一个 Tab 停靠点,进组后四个方向键都能切换

套餐
免费版
标准版
专业版

组件结构 ​

加粗的是必需部件。

data-scope="radio-group":root · label · item · item-text · indicator · hidden-input

示例 ​

受控 ​

传入 value 后由宿主决定;值可以是 null,表示没有任何一项选中

套餐
免费版
标准版
当前:free

横向排布 ​

orientation 只影响排版与 aria-orientation,方向键四个方向照样都能切换

尺寸
小
中
大

禁用 ​

单项禁用后不可点击,方向键也跳过它;整组禁用则每一项都随之禁用

单项禁用
免费版
专业版
整组禁用
免费版
专业版

颜色 ​

tone 决定选中圆点使用哪族颜色,六种语气各一组

brand
选中
未选
neutral
选中
未选
success
选中
未选
warning
选中
未选
danger
选中
未选
info
选中
未选

尺寸 ​

size 改变条目间距与字号,不写即默认中档

sm
免费版
标准版
缺省
免费版
标准版
lg
免费版
标准版

数据驱动 ​

数据字段的命名由数据决定,映射为条目的值、文本与禁用即可

优先级
紧急
高
普通
低
当前:p1

设计指引 ​

何时使用 ​

  • 二到五个互斥选项,且各选项的文字值得同时展开供用户比较。

何时不用 ​

特性 ​

  • 整组只占一个 Tab 位,组内靠方向键移动,与原生单选组一致。
  • hidden-input 承担表单参与。
  • collection 可数据驱动,也可以逐项编写。
  • 圆圈是字段家族的控制盒:不填底、描边与无影,选中后以语气色圆点填充;整行接 Action Control row 档,悬停 / 按下换面不缩放,圆圈随行换到承载面阶梯的下一档。
  • 与复选框的不对称是有意的:一个复选框自身即成立(勾选同意条款),一个单选按钮自身不成立,因此复选框有独立组件、单选按钮没有。

组合 ​

  • 外层放表单字段;每项的补充说明放进选项内容。

最佳实践 ​

  • 提供默认选中项,除非“未选”本身有意义。
  • 选项文字写完整,不依赖共同前缀省略。

反模式 ​

  • 单选组只有一个选项,用户无从选择。
  • 选项可以被取消选中:单选组一旦选中就不应回到空值,需要空值时增加一项“不指定”。

API 参考 ​

产物 ​

层值
自定义元素<xh-radio-group>
Vue 组件XhRadioGroupItem XhRadioGroupItemText XhRadioGroupLabel XhRadioGroupRoot
组合式函数useRadioGroup
状态机radioGroupMachine
皮肤@xihan-ui/styles/radio-group.css

Props ​

属性类型必填说明
collectionRadioGroupNode[]条目数据,显示文本与禁用的事实源。提供后条目部件只需声明 value。 未提供时回到文本与禁用都写在条目部件上的方式。
valuestring | null
defaultValuestring | null
disabledboolean
readOnlyboolean只读:不可选择,但仍可聚焦、方向键照常移动焦点,对比度不降低。
invalidboolean校验失败:只改变呈现,不阻止交互。
requiredboolean必填:随表单校验一起使用,只发无障碍属性,不自行拦截提交。
orientationOrientation
dirDirection文字方向,默认 'ltr'。
namestring表单字段名。
toneTone语气:brand / neutral / success / warning / danger / info,决定使用哪族颜色。
sizeSize尺寸:sm / md / lg。
onValueChange(details: RadioGroupValueChangeDetails) => voidvalue 变化回调。

RadioGroupNode ​

collection 的元素。

字段类型必填说明
valuestring是
labelstring展示文本;默认回退为 value。
disabledboolean条目禁用:方向键跳过它,但它仍可聚焦、仍是导航起点。

事件 ​

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
value-changeRadioGroupValueChangeDetails选中值变化;detail 为 { value: string | null }

React 适配器 props ​

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

React 组件属性类型必填说明
XhRadioGroupItemvaluestring是
XhRadioGroupItemdisabledboolean默认交给 connect 查询 collection,写死 false 会覆盖数据中的禁用。
XhRadioGroupRootlabelReactNode标题文字。提供后不必再写 label 部件。
XhRadioGroupRootrenderItem(node: RadioGroupNodeMeta) => ReactNode每个条目的自定义内容;未提供时使用 collection 中的 label。
XhRadioGroupRootchildrenReactNode

状态 ​

公开状态写入 data-state。

部件取值
item'checked' | 'unchecked'
item-text'checked' | 'unchecked'
indicator'checked' | 'unchecked'
hidden-input'checked' | 'unchecked'

以下名称仅用于内部状态机。

状态:idle

事件:VALUE.SET · ITEM.SELECT · ITEM.FOCUS · GROUP.BLUR · FORM.RESET · PRESS.START · PRESS.END

判据:canPress

connect API ​

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

成员类型说明
valuestring | null
collectionreadonly RadioGroupNodeMeta[]由 collection 推导的条目元信息,按数据顺序排列;未提供 collection 时为空数组。
focusedValuestring | null焦点在组外时为 null。
setValue(next: string) => void
getRootProps() => T['element']
getLabelProps() => T['element']
getItemProps(props: RadioGroupItemProps) => T['element']
getItemTextProps(props: RadioGroupItemProps) => T['element']
getIndicatorProps(props: RadioGroupItemProps) => T['element']
getHiddenInputProps(props: RadioGroupItemProps) => T['input']条目对应的隐藏原生 radio 输入,用于表单提交。

无障碍 ​

键盘 ​

规格出处:W3C APG

按键生效条件行为
Tab / Shift+Tabfocus outside the group整组只占一个 Tab 位:焦点进入锚点条目(即选中项);落到容器上时由容器转投锚点条目,锚点缺席或被禁用才落首个可停留项
ArrowDown / ArrowRightfocus in group, group not disabled焦点移到下一个可停留条目并选中,末项回绕到首项;dir=rtl 时改由 ArrowLeft 承担
ArrowUp / ArrowLeftfocus in group, group not disabled焦点移到上一个可停留条目并选中,首项回绕到末项;dir=rtl 时改由 ArrowRight 承担
Spacefocus on item, item not disabled选中当前条目
Spaceheld on item, 条目未禁用且组未禁用、非只读按住期间该条目投影 data-pressed,与指针 :active 同一副按压面(行与圆圈一起换面);抬起或失焦撤下,按住途中整组转入禁用或只读也撤下。role=radio 只有 Space 是激活键,Enter 不进按压面;选中与按压互相独立

ARIA ​

以下属性由 connect 生成。

部件属性值
rootaria-invalid'true' | 'false'
rootaria-labelledbylabel 部件的 id
rootaria-orientationprops.orientation
rootaria-readonly'true' | 'false'
rootaria-required'true' | 'false'
rootrole'radiogroup'
itemaria-checked'true' | 'false'
itemaria-disabled'true' | 'false'
itemrole'radio'
indicatoraria-hidden'true'
hidden-inputaria-hidden'true'

样式参考 ​

皮肤 ​

@xihan-ui/styles/radio-group.css 使用 [data-scope="radio-group"][data-part="root"] 部件选择器,位于 xihan.components 层。覆盖样式使用 xihan.overrides。

forced-colors: active 下另有一套规则:颜色交给系统,边框与状态标记改用系统色关键字。

数据属性 ​

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

部件属性值
rootdata-disabled''(条件成立时才出现)
rootdata-invalid''(条件成立时才出现)
rootdata-orientationprops.orientation
rootdata-readonly''(条件成立时才出现)
rootdata-required''(条件成立时才出现)
rootdata-sizeprops.size
rootdata-toneprops.tone
itemdata-disabled''(条件成立时才出现)
itemdata-invalid''(条件成立时才出现)
itemdata-pressed''(条件成立时才出现)
itemdata-readonly''(条件成立时才出现)
itemdata-state'checked' | 'unchecked'
itemdata-xh-action-control''
itemdata-xh-action-display'always'
itemdata-xh-action-profile'row'
itemdata-xh-action-size'xs'
itemdata-xh-action-variant'ghost'
item-textdata-disabled''(条件成立时才出现)
item-textdata-invalid''(条件成立时才出现)
item-textdata-readonly''(条件成立时才出现)
item-textdata-state'checked' | 'unchecked'
indicatordata-disabled''(条件成立时才出现)
indicatordata-invalid''(条件成立时才出现)
indicatordata-readonly''(条件成立时才出现)
indicatordata-state'checked' | 'unchecked'
hidden-inputdata-disabled''(条件成立时才出现)
hidden-inputdata-invalid''(条件成立时才出现)
hidden-inputdata-readonly''(条件成立时才出现)
hidden-inputdata-state'checked' | 'unchecked'

CSS 变量 ​

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

变量部件CSS 属性状态默认来源说明
--xh-radio-group-gaprootgapdefault--xh-space-2radio-group 的 root 部件 gap 覆盖槽。
--xh-radio-group-indicator-bgindicatorbackgrounddefaulttransparentradio-group 的 indicator 部件 background 覆盖槽。
--xh-radio-group-indicator-bg-disabledindicator
item
backgrounddisabled--xh-bg-subtleradio-group 的 indicator、item 部件 background 覆盖槽。
--xh-radio-group-indicator-bg-pressedindicator
item
backgrounddisabled
is(:active, [data-pressed])
not([data-disabled])
not([data-readonly])
pressed
readonly
--xh-_radio-group-host-bg-pressedradio-group 的 indicator、item 部件 background 覆盖槽。
--xh-radio-group-indicator-borderindicatorborderdefault--xh-border-controlradio-group 的 indicator 部件 border 覆盖槽。
--xh-radio-group-indicator-border-checkedindicatorborder-colorstate=checked--xh-_radio-group-accentradio-group 的 indicator 部件 border-color 覆盖槽。
--xh-radio-group-indicator-border-disabledindicator
item
border-colordisabled--xh-border-defaultradio-group 的 indicator、item 部件 border-color 覆盖槽。
--xh-radio-group-indicator-border-hoverindicator
item
border-colordisabled
hover
invalid
not([data-disabled])
not([data-invalid])
not([data-readonly])
not([data-state='checked'])
readonly
state=checked
--xh-border-control-hoverradio-group 的 indicator、item 部件 border-color 覆盖槽。
--xh-radio-group-indicator-border-invalidindicatorborder-colorinvalid
state=checked
--xh-border-invalidradio-group 的 indicator 部件 border-color 覆盖槽。
--xh-radio-group-indicator-dotindicatorbackgrounddefault--xh-_radio-group-accentradio-group 的 indicator 部件 background 覆盖槽。
--xh-radio-group-indicator-dot-disabledindicator
item
backgrounddisabled--xh-fg-disabledradio-group 的 indicator、item 部件 background 覆盖槽。
--xh-radio-group-indicator-dot-pressedindicator
item
backgrounddisabled
is(:active, [data-pressed])
not([data-disabled])
not([data-readonly])
pressed
readonly
state=checked
--xh-_tone-activeradio-group 的 indicator、item 部件 background 覆盖槽。
--xh-radio-group-indicator-radiusindicatorborder-radiusdefault--xh-shape-circleradio-group 的 indicator 部件 border-radius 覆盖槽。
--xh-radio-group-indicator-sizeindicatorblock-size
inline-size
default--xh-_radio-group-indicatorradio-group 的 indicator 部件 block-size、inline-size 覆盖槽。
--xh-radio-group-item-bg-hoveritembackground-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-bg-subtleradio-group 的 item 部件 background-color 覆盖槽。
--xh-radio-group-item-bg-presseditembackground-colordisabled
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-bg-subtle-hoverradio-group 的 item 部件 background-color 覆盖槽。
--xh-radio-group-item-fgitemcolordefault
disabled
focus-visible
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-fg-defaultradio-group 的 item 部件 color 覆盖槽。
--xh-radio-group-item-fg-disableditemcolordisabled--xh-fg-disabledradio-group 的 item 部件 color 覆盖槽。
--xh-radio-group-item-font-sizeitemfont-sizedefault--xh-_radio-group-font-sizeradio-group 的 item 部件 font-size 覆盖槽。
--xh-radio-group-item-gapitemgapdefault--xh-_radio-group-item-gapradio-group 的 item 部件 gap 覆盖槽。
--xh-radio-group-item-radiusitemborder-radiusdefault--xh-shape-controlradio-group 的 item 部件 border-radius 覆盖槽。
--xh-radio-group-label-fglabelcolordefault--xh-fg-mutedradio-group 的 label 部件 color 覆盖槽。
--xh-radio-group-label-fg-disabledlabel
root
colordisabled--xh-fg-subtleradio-group 的 label、root 部件 color 覆盖槽。
--xh-radio-group-label-font-sizelabelfont-sizedefault--xh-text-label-sizeradio-group 的 label 部件 font-size 覆盖槽。
--xh-radio-group-label-font-weightlabelfont-weightdefault--xh-text-label-weightradio-group 的 label 部件 font-weight 覆盖槽。

动效 ​

动效角色:按压 · 状态 · 切换(见动效规范)。

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

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

响应式 ​

皮肤另按输入能力分档:pointer: coarse:同一份皮肤在触屏与带指针的设备上不一样,与视口宽度无关。

RTL ​

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像。

Released under The MIT License