
Radix Vue Tabs 组件 TabsRoot 完整指南受控状态、方向、激活模式与键盘导航实现解析【免费下载链接】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导读Tabs标签页是一组分层排列的内容区块——即 tab panel标签面板同一时刻只展示其中一个。在 radix-vueRadix Vue本仓库即其源码实现现已演进为 reka-ui中TabsRoot是整套 Tabs 组件的状态中枢它持有当前激活值、方向与激活模式等共享上下文并通过 Context 注入给TabsList、TabsTrigger、TabsContent、TabsIndicator等子部件。读完本文你将掌握TabsRoot全部 Props / Events / Slots 的含义与默认值理解受控与非受控模式、自动/手动激活、横向/纵向布局与 RTL 支持在源码中的落点并能在实际项目中写出可复现、可运行、符合 WAI-ARIA Tabs 模式的完整标签页。组件定位与 AnatomyTabsRoot位于packages/core/src/Tabs/TabsRoot.vue是 Tabs 组件的根容器Contains all the tabs component parts。完整装配通常包含五个部分script setup import { TabsContent, TabsIndicator, TabsList, TabsRoot, TabsTrigger } from reka-ui /script template TabsRoot TabsList TabsIndicator / TabsTrigger / /TabsList TabsContent / /TabsRoot /template组件结构一览见 packages/core/src/Tabs部件文件职责TabsRootTabsRoot.vue状态中枢提供共享 ContextTabsListTabsList.vue沿激活内容边缘排列触发器的容器roletablistTabsTriggerTabsTrigger.vue激活对应内容的按钮roletabTabsIndicatorTabsIndicator.vue高亮当前激活标签的指示器TabsContentTabsContent.vue与触发器关联的内容面板roletabpanel在根节点上TabsRoot会把dir与data-orientation透传到最外层渲染元素同时通过provideTabsRootContext注入modelValue、orientation、dir、unmountOnHide、activationMode、baseId、tabsList、contentIds及注册/注销 content 的回调TabsRoot.vue子部件全部通过injectTabsRootContext()获取这些状态。Props 全面解析TabsRootPropsT继承自PrimitiveProps泛型T extends StringOrNumber即string | number决定了标签 value 的类型。以下表格来自 docs/content/meta/TabsRoot.md并结合源码TabsRoot.vue补充了默认值语义NameDescriptionTypeRequiredDefaultactivationMode标签是在聚焦时自动激活还是在点击时手动激活。automatic \| manualNoautomaticas组件渲染成的元素或组件可被asChild覆盖。AsTag \| ComponentNodivasChild将默认渲染元素改为传入的子元素合并其 props 与行为。详见 Composition 指南。booleanNo-defaultValue初始渲染时激活的标签值。用于不需要控制 tabs 状态非受控的场景。TNo-dir阅读方向。省略时继承自全局ConfigProvider否则假定 LTR。ltr \| rtlNo-modelValue受控模式下要激活的标签值可通过v-model绑定。TNo-orientation标签的布局方向主要用于决定箭头导航方向左右 vs 上下。vertical \| horizontalNohorizontalunmountOnHide为true时关闭隐藏状态下元素会被卸载。booleanNotrue受控与非受控模式modelValue / defaultValue源码中通过useVModel统一处理两种模式TabsRoot.vueconst modelValue useVModelTabsRootPropsT, modelValue, update:modelValue(props, modelValue, emits, { defaultValue: props.defaultValue, passive: (props.modelValue undefined) as false, })传入modelValue并配合v-model即为受控模式激活值完全由外部状态决定切换标签会触发update:modelValue事件不传modelValue、只传defaultValue即为非受控模式内部自行维护状态defaultValue仅作为初始值后续切换不再同步回外部。泛型T允许 value 为字符串或数字。注意官方示例中存在:value1数字与valuetab2字符串混用的写法见 story/_Tabs.vue源码对二者均支持但同一组标签内应保持 value 类型一致以免触发值比较问题。方向 dir继承 ConfigProvider、支持 RTLdir的取值逻辑在 TabsRoot.vueconst { orientation, unmountOnHide, dir: propDir } toRefs(props) const dir useDirection(propDir)useDirection会在未显式传入dir时向全局ConfigProvider查询阅读方向缺省假定 LTR。该方向随后被传递给TabsList内部的RovingFocusGroup决定左右方向键的移动顺序并作为dir属性渲染到根元素上。渲染控制as / asChildTabsRoot默认渲染为div并通过Primitive组件对外渲染TabsRoot.vuePrimitive :dirdir :data-orientationorientation :as-childasChild :asas slot :model-valuemodelValue / /Primitiveas指定渲染为任意元素或组件如assectionasChild将根元素替换为你传入的单个子元素并把组件的行为、属性合并到该元素上适合与现有语义化标记或自定义组件组合。卸载策略 unmountOnHide默认true即标签内容在隐藏时会被卸载配合Presence组件实现。若设为false内容面板仅通过hidden属性隐藏而保留在 DOM 中可用于需要保持内部状态如表单输入或配合动画库的场景。其实际消费点在 TabsContent.vueslot v-ifrootContext.unmountOnHide.value ? present : true /。Events 与 SlotsTabsRoot对外仅暴露一个事件与一个插槽见 docs/content/meta/TabsRoot.mdEventsNameDescriptionTypeupdate:modelValue值变化时调用的事件处理器[payload: T]该事件由useVModel驱动受控模式下任何切换点击、聚焦自动激活、键盘操作最终都会走到changeModelValue并写入modelValue进而触发update:modelValueTabsRoot.vue。SlotsNameDescriptionTypemodelValue当前输入值T默认插槽接收modelValue作为 slot prop方便在根内部访问当前激活值例如TabsRoot v-slot{ modelValue }。源码级实现细节子部件的共享上下文TabsRoot提供的关键 Context 成员及消费方tabsList由TabsList挂载时通过context.tabsList currentElement回写TabsList.vue供TabsIndicator查询激活 tab 的位置contentIds/registerContent/unregisterContentTabsContent在onMounted时注册自己的 value、在卸载前注销TabsContent.vue。这样TabsTrigger可以只对确实存在对应内容的触发器输出aria-controls——测试 Tabs.test.ts 专门验证了这一行为baseId由useId(undefined, reka-tabs)生成随后通过 utils.ts 的makeTriggerId/makeContentId派生出${baseId}-trigger-${value}与${baseId}-content-${value}关联 ID。自动激活 activationMode 的落点activationMode本身在 Root 中只做透传TabsRoot.vue真正消费它的是TabsTrigger的focus处理器TabsTrigger.vueconst isAutomaticActivation rootContext.activationMode ! manual; if (!isSelected !disabled isAutomaticActivation) { rootContext.changeModelValue(value); }automatic默认键盘聚焦或 Tab 键移入时即激活对应标签符合移动端与多数桌面端的预期manual仅当用户点击或按 Enter / Space 时才激活keydown.enter.spacerootContext.changeModelValue(value)聚焦本身不改变激活值。鼠标点击的精细处理TabsTrigger对mousedown.left做了特殊处理TabsTrigger.vue仅响应左键且未按住 Ctrl避开 macOS 右键触发的mousedown否则preventDefault()阻止聚焦避免误激活。与 RovingFocusGroup 的协作TabsList将自身包裹在RovingFocusGroup中TabsList.vue把orientation、dir、loop默认true支持在首尾标签间循环传入每个TabsTrigger则由RovingFocusItem包裹TabsTrigger.vue。这构成了完整的键盘焦点管理链路上下左右箭头按方向移动焦点、Home/End 跳到首尾、Tab 键在 tablist 与 tabpanel 间切换。数据属性与无障碍根与列表渲染[data-orientationvertical|horizontal]触发器渲染[data-stateactive|inactive]、禁用时渲染[data-disabled]并输出aria-selected、aria-controls仅当有匹配内容时与roletab内容渲染[data-state]与[data-orientation]输出roletabpanel、aria-labelledby指向对应触发器且tabindex0使面板可聚焦TabsContent.vue。以上属性使组件整体遵循 WAI-ARIA Tabs 设计模式。测试套件通过axe自动检查无障碍违规Tabs.test.ts并验证了 ArrowRight 切换焦点与内容渲染行为Tabs.test.ts。实战示例基础用法非受控 自动激活script setup import { TabsContent, TabsList, TabsRoot, TabsTrigger } from reka-ui /script template TabsRoot default-valueaccount classflex flex-col w-[300px] TabsList classflex border-b aria-labelManage your account TabsTrigger classpx-5 h-[45px] flex-1 valueaccount Account /TabsTrigger TabsTrigger classpx-5 h-[45px] flex-1 valuepassword Password /TabsTrigger /TabsList TabsContent valueaccount Make changes to your account here. /TabsContent TabsContent valuepassword Change your password here. /TabsContent /TabsRoot /template完整可运行示例可参考 story/_Tabs.vue 与 TabsVertical.story.vue。受控模式script setup import { ref } from vue import { TabsContent, TabsList, TabsRoot, TabsTrigger } from reka-ui const activeTab ref(tab1) /script template TabsRoot v-modelactiveTab TabsList aria-labelcontrolled tabs TabsTrigger valuetab1One/TabsTrigger TabsTrigger valuetab2Two/TabsTrigger /TabsList TabsContent valuetab1Tab one content/TabsContent TabsContent valuetab2Tab two content/TabsContent /TabsRoot /template纵向布局设置orientationvertical后箭头导航自动切换为上下方向左右键逻辑由内部RovingFocusGroup按方向重新映射并渲染data-orientationverticalTabsRoot default-valuetab1 orientationvertical TabsList aria-labeltabs example TabsTrigger valuetab1One/TabsTrigger TabsTrigger valuetab2Two/TabsTrigger TabsTrigger valuetab3Three/TabsTrigger /TabsList TabsContent valuetab1Tab one content/TabsContent TabsContent valuetab2Tab two content/TabsContent TabsContent valuetab3Tab three content/TabsContent /TabsRoot手动激活模式将activationMode设为manual聚焦只移动焦点、不切换面板点击或按 Enter/Space 才激活TabsRoot default-valuetab1 activation-modemanual !-- ... -- /TabsRoot键盘交互参考根据官方文档docs/content/docs/components/tabs.md中列出的键盘表并对照RovingFocusGroup/RovingFocusItem的实现按键行为Tab焦点进入 tabs 时聚焦当前激活的触发器触发器聚焦时将焦点移至激活的内容面板ArrowDown依orientation将焦点移至下一个触发器并激活其内容ArrowRight依orientation将焦点移至下一个触发器并激活其内容ArrowUp依orientation将焦点移至上一个触发器并激活其内容ArrowLeft依orientation将焦点移至上一个触发器并激活其内容Home焦点移至第一个触发器并激活其内容End焦点移至最后一个触发器并激活其内容TabsList的loop属性默认为true即在首尾之间循环移动焦点将其设为false可禁用循环。更多阅读组件主文档docs/content/docs/components/tabs.mdAPI 元数据docs/content/meta/TabsRoot.md源码目录packages/core/src/Tabs测试用例packages/core/src/Tabs/Tabs.test.ts指南文档docs/content/docs/guides下的 Composition、Styling、Animation 等章节覆盖asChild组合、数据属性样式与 Presence 动画相关主题。【免费下载链接】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),仅供参考