
掌握 Radix Vue SelectGroup从 Props 到可访问性实现的完整指南【免费下载链接】radix-vueAn open-source UI component library for building high-quality, accessible design systems and web apps for Vue. Previously Radix Vue项目地址: https://gitcode.com/GitHub_Trending/ra/radix-vue导读SelectGroup是 Radix Vue现 Reka UISelect 组件体系中用于把多个SelectItem归组展示的容器组件。它本身渲染为带有rolegroup语义的分组元素并与SelectLabel配合实现 WAI-ARIA 标准下的自动标签关联accessibility。本文以 SelectGroup 组件文档 为主体结合仓库源码SelectGroup.vue、SelectLabel.vue与真实示例_Select.vue帮助你彻底掌握该组件的 Props 用法、源码实现原理以及如何写出可无障碍访问的分组下拉菜单。一、SelectGroup 是什么在 Radix Vue 的 Select 组件分层中一个完整的选择框由SelectRoot、SelectTrigger、SelectPortal、SelectContent、SelectViewport、SelectItem等部件组合而成。当选项数量较多、需要按类别组织时SelectGroup与SelectLabel就是用来给选项分组的标配SelectGroup选项组容器负责承载同一类别的多个SelectItemSelectLabel组的标题标签渲染在SelectGroup内部顶部SelectSeparator可选的视觉分隔线用于组与组之间详见 Select 文档。从文档中的标准结构可以看到二者总是成对出现SelectViewport SelectItem SelectItemText / SelectItemIndicator / /SelectItem SelectGroup SelectLabel / SelectItem SelectItemText / SelectItemIndicator / /SelectItem /SelectGroup SelectSeparator / /SelectViewportSelectGroup 自身不参与值的选择与状态管理它只解决组织与语义标注两个问题。二、SelectGroup 的 Props 详解SelectGroup继承自PrimitiveProps见 SelectGroup.vue因此对外暴露的 Props 只有两个NameDescriptionTypeRequiredDefaultasThe element or component this component should render as. Can be overwritten by asChild.AsTag \| ComponentNodivasChildChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details.booleanNo-1.as自定义渲染元素默认情况下SelectGroup渲染为div。通过as可以将其改为任意原生标签如ul、section或自定义组件。PrimitiveProps中as的类型为AsTag | Component其中AsTag在 Primitive.ts 中定义了完整的合法标签集合包括a、button、div、form、label、ul、ol、li、span等同时也接受任意自定义字符串与组件对象。2.asChild合并子元素渲染asChild为true时SelectGroup不再渲染自己的根元素而是将自身的 props 与行为合并到你传入的唯一子元素上基于 Slot 透传实现。这是 Radix Vue 的 Composition 模式的核心用法适用于需要在既有元素上叠加组件行为、又不想引入多余 DOM 嵌套的场景。3. 源码层的默认值验证PrimitiveProps接口定义Primitive.ts与Primitive组件运行时声明Primitive.ts保持一致asChild默认falseas默认div类型校验支持String | Object组件对象。这意味着在未传任何 Props 时SelectGroup 等价于渲染一个带语义属性的div。三、源码实现角色、标签与上下文SelectGroup的实现非常精简但承载了关键的语义与关联机制。完整源码如下SelectGroup.vuescript langts import type { PrimitiveProps } from /Primitive import { createContext, useId } from /shared export interface SelectGroupProps extends PrimitiveProps {} interface SelectGroupContext { id: string } export const [injectSelectGroupContext, provideSelectGroupContext] createContextSelectGroupContext(SelectGroup) /script script setup langts import { Primitive } from /Primitive const props definePropsSelectGroupProps() const id useId(undefined, reka-select-group) provideSelectGroupContext({ id }) /script template Primitive rolegroup v-bindprops :aria-labelledbyid slot / /Primitive /template1.rolegroup无障碍语义的核心SelectGroup渲染的根元素固定带有rolegroup。根据 WAI-ARIA 规范group角色用于把一组相关的 UI 对象组织起来使屏幕阅读器能够将其识别为一个整体并为后续的标签关联提供挂载点。2.useIdprovide/inject自动标签关联机制这是整个组件最值得注意的实现细节组件挂载时调用useId(undefined, reka-select-group)生成一个唯一 ID通过provideSelectGroupContext({ id })将该 ID 注入到组件树中根元素同时绑定:aria-labelledbyid告诉辅助技术这个分组的标签是 ID 为id的元素。而在 SelectLabel.vue 中SelectLabel通过injectSelectGroupContext({ id: })取出这个 ID并把自己的id属性设置为该值Primitive v-bindprops :idgroupContext.id slot / /Primitive这样就形成了完整的关联闭环组容器的aria-labelledby指向标签的id标签的id又来自组容器注入的同一个 ID。只要把SelectLabel放进SelectGroup内部无需任何手动传参二者就自动建立了无障碍标签关系。这也是为什么文档强调use in conjunction withSelectLabelto ensure good accessibility via automatic labelling配合 SelectLabel 使用通过自动标签确保良好的可访问性。3.SelectGroupContext的导出价值injectSelectGroupContext同时通过 index.ts 对外导出。这意味着在编写自定义 Select 扩展组件时也可以主动注入该上下文复用同一套自动标签机制。四、实战示例构建带分组的下拉菜单仓库中的 story 文件_Select.vue提供了完整的可运行示例展示了Fruits / Vegetables两组选项的写法SelectViewport classp-[5px] SelectLabel classpx-[25px] text-xs leading-[25px] text-mauve11 Fruits /SelectLabel SelectGroup SelectItem v-for(option, index) in options :keyindex classtext-[13px] leading-none text-violet11 rounded-[3px] flex items-center h-[25px] pr-[35px] pl-[25px] relative select-none contenteditable="false">【免费下载链接】radix-vueAn open-source UI component library for building high-quality, accessible design systems and web apps for Vue. Previously Radix Vue项目地址: https://gitcode.com/GitHub_Trending/ra/radix-vue创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考