返回目录
组件详情入口
导航
@vean/ui
STabs

Tabs

Tabs 属于 导航 分类。建议先看演示与用法,再对照 API 表格完成接入和样式调整。

先用快捷跳转面板找到概述、用法、演示和 API,再往下细读完整文档内容。

快速跳转

同分类组件

如果你在同一类交互里做组合,这些组件通常会一起出现。

标签页

概述

一组分层的内容区块——即标签面板——一次只显示一个。

特性

  • WAI-ARIA 标签页模式 — 列表渲染为 tablist,触发器为 role="tab",面板为 role="tabpanel";活动标签带 aria-selected,每个触发器通过 aria-controls/aria-labelledby 关联面板,aria-orientation 反映布局方向。
  • 数据驱动的 Compact 组合 — STabs 将条目迭代、默认触发器/内容组合与指示器渲染委托给泛型 Aria TabsCompact<T>,由它负责每个条目的 ARIA 接线。
  • 受控/非受控状态 — modelValue 支持 v-model(受控);defaultValue 提供非受控用法,底层基于 useControllableState。
  • 两种激活模式 — activationMode: 'automatic' 在聚焦时激活标签(ARIA 默认);'manual' 仅在点击 / Enter / Space 时激活。
  • 完整键盘导航 — useRovingFocusGroup 提供方向键(与 Home/End)移动并跳过禁用标签;Enter / Space 激活聚焦的标签。
  • 基于 Presence 的内容挂载 — unmountOnHide: true(默认)在退出动画后卸载非活动面板;false 保持所有面板挂载但带 hidden 属性;forceMount 无条件将面板保留在 DOM 中。
  • 动画指示器 — 滑动指示器通过 CSS 变量(--vean-tabs-indicator-size / --vean-tabs-indicator-position)追踪活动标签,由 ResizeObserver 测量并在值/方向变化时重新定位;RTL 偏移自动镜像。
  • 水平与垂直布局 — orientation: 'vertical' 纵向堆叠列表并让指示器沿块轴移动。
  • 三个自定义插槽 — trigger(scoped { ...item, active })、content(scoped { ...item, active })与 indicator。
  • 六种视觉变体 — size(xs…2xl)、orientation(horizontal / vertical)、shape(square / rounded)、fill(full / auto)与 enableIndicator(回退为实心活动触发器样式),通过 tabsVariants 的 scv() 配方应用。
  • Aria 组合 — TabsRoot / TabsList / TabsTrigger / TabsContent / TabsIndicator / TabsCompact 均可从 @vean/aria/tabs 导入,用于完全自定义样式构建。

用法

STabs 现在将条目迭代、默认触发器/内容组合与指示器渲染委托给 Aria 的 TabsCompact。如需无样式、数据驱动的用法,请从 @vean/aria/tabs 导入 TabsCompact。

演示

基础

The Tab Content: 1

自定义

The Tab Content: 1
The Tab Content: 1

API

Aria 层

7

Tabs<T>

18 属性1 事件3 插槽
属性
属性名类型默认值描述
class
ClassValue
—
应用于根元素的额外类名。
size
ThemeSize
—
组件的视觉尺寸。
ui
Partial<TabsUi>
—
带样式的选项卡 UI 插槽,包括用于紧凑型指示器主体的 `indicatorContent`。
fill
TabsFill
—
填充。
shape
TabsShape
—
组件的结构。
items
T[]
—
由该组件渲染的项。
enableIndicator
boolean
—
是否启用指示器。
listProps
TabsListProps
—
转发给列表元素的属性。
triggerProps
TabsTriggerProps
—
转发给触发元素的属性。
contentProps
TabsContentProps
—
转发给内容元素的属性。
indicatorProps
TabsIndicatorProps
—
转发给 indicator 元素的属性。
modelValue
T['value'] | null
—
用于激活的选项卡的受控值。可作为 `v-model` 进行绑定。
defaultValue
T['value'] | null
—
初始渲染时应处于活动状态的标签页的值。当您无需控制标签页的状态时使用此选项
activationMode
TabsActivationMode
automatic
Tab 键是自动激活(获得焦点时)还是手动激活(点击时)。
unmountOnHide
boolean
`true`
当值为 `true` 时,该元素将在关闭状态下被卸载。
dir
Direction
—
项目之间的导航方向。
loop
boolean
false
键盘导航是否应循环往复
orientation
DataOrientation
—
该组的取向。主要是为了确保箭头导航能据此正确进行(左右与上下)。
事件
事件名参数描述
update:modelValue
Exclude<T, undefined>
当值发生变化时调用的事件处理程序
插槽
插槽名参数描述
trigger
T & { selected: boolean; }
触发槽的自定义内容。
content
T & { selected: boolean; }
内容插槽的自定义内容。
indicator
—
指示器插槽的自定义内容。

TabsCompact<T>

13 属性1 事件3 插槽
属性
属性名类型默认值描述
items
T[]
—
由该组件渲染的项。
enableIndicator
boolean
—
是否启用指示器。
listProps
TabsListProps
—
转发给列表元素的属性。
triggerProps
TabsTriggerProps
—
转发给触发元素的属性。
contentProps
TabsContentProps
—
转发给内容元素的属性。
indicatorProps
TabsIndicatorProps
—
转发给 indicator 元素的属性。
modelValue
T['value'] | null
—
用于激活的选项卡的受控值。可作为 `v-model` 进行绑定。
defaultValue
T['value'] | null
—
初始渲染时应处于活动状态的标签页的值。当您无需控制标签页的状态时使用此选项
activationMode
TabsActivationMode
automatic
Tab 键是自动激活(获得焦点时)还是手动激活(点击时)。
unmountOnHide
boolean
`true`
当值为 `true` 时,该元素将在关闭状态下被卸载。
dir
Direction
—
项目之间的导航方向。
loop
boolean
false
键盘导航是否应循环往复
orientation
DataOrientation
—
该组的取向。主要是为了确保箭头导航能据此正确进行(左右与上下)。
事件
事件名参数描述
update:modelValue
Exclude<T, undefined>
当值发生变化时调用的事件处理程序
插槽
插槽名参数描述
trigger
T & { selected: boolean; }
触发槽的自定义内容。
content
T & { selected: boolean; }
内容插槽的自定义内容。
indicator
—
指示器插槽的自定义内容。

TabsContent

2 属性
属性
属性名类型默认值描述
value
DefinedValue
—
一个将内容与触发器关联起来的唯一值。
forceMount
boolean
—
用于在需要更多控制时强制挂载。 在使用 Vue 动画库控制动画时非常有用。

TabsIndicator

2 属性
属性
属性名类型默认值描述
asChild
boolean
—
将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。
as
AsTag | Component
'div'
该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。

TabsList

TabsRoot<T>

7 属性1 事件
属性
属性名类型默认值描述
modelValue
T
—
用于激活的选项卡的受控值。可作为 `v-model` 进行绑定。
defaultValue
T
—
初始渲染时应处于活动状态的标签页的值。当您无需控制标签页的状态时使用此选项
activationMode
TabsActivationMode
automatic
Tab 键是自动激活(获得焦点时)还是手动激活(点击时)。
unmountOnHide
boolean
`true`
当值为 `true` 时,该元素将在关闭状态下被卸载。
dir
Direction
—
项目之间的导航方向。
loop
boolean
false
键盘导航是否应循环往复
orientation
DataOrientation
—
该组的取向。主要是为了确保箭头导航能据此正确进行(左右与上下)。
事件
事件名参数描述
update:modelValue
Exclude<T, undefined>
当值发生变化时调用的事件处理程序

TabsTrigger

4 属性
属性
属性名类型默认值描述
value
DefinedValue
—
一个将触发器与内容关联起来的唯一值。
disabled
boolean
—
当值为 `true` 时,禁止用户与该选项卡进行交互。
asChild
boolean
—
将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。
as
AsTag | Component
'div'
该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。

备注

架构与竞品对比

关注点VeanUIshadcn-vue / Radix TabsAnt Design TabsElement Plus Tabs
Aria / 样式双层分离✅ @vean/aria/tabs + scv()✅ Aria 原语❌ 单一包❌ 单一包
数据驱动 Compact API✅ 泛型 TabsCompact<T> + items✅ TabList/Tab/TabPanel 部件✅ 配置驱动(items)✅ 配置驱动
受控/非受控✅ modelValue / defaultValue✅ modelValue / defaultValue✅ activeKey / defaultActiveKey✅ v-model
激活模式✅ automatic / manual✅❌(始终自动)❌(始终自动)
键盘导航✅ roving focus(方向键/Home/End)+ Enter/Space✅ roving focus✅ 方向键 / Home / End✅ 方向键
禁用标签跳过✅ roving focus 跳过禁用条目✅✅✅
Presence / forceMount 内容✅ unmountOnHide + forceMount + 退出动画✅ forceMount❌❌
动画指示器✅ CSS 变量 + ResizeObserver + RTL 镜像❌(无内置指示器)✅ ink bar(line 类型)❌
水平 + 垂直✅ orientation✅✅ tabPosition✅ tab-position
变体系统✅ size × orientation × shape × fill❌(自行定制样式)✅ type / size / tabBarGutter✅ type / size
自定义插槽✅ trigger / content / indicator✅ 部件级✅ label / children✅ label / icon
ARIA 接线(controls/labelledby)✅ 每项自动接线✅ 自动✅✅

运行时注意事项

  1. 聚焦激活 — activationMode: 'automatic'(默认)下,通过键盘聚焦标签(或 ArrowRight/ArrowLeft)即激活;'manual' 下仅点击或按 Enter/Space 激活。
  2. 指示器测量 — 指示器在列表 ref 挂载后、值/方向变化时与尺寸变化时对活动触发器定位;仅在首次成功测量后渲染。
  3. RTL 定位 — dir: 'rtl' 下指示器偏移被镜像(list.clientWidth - offsetLeft - offsetWidth),CSS rtl:-translate-x-… 翻转位移,指示器始终锚定活动标签。
  4. 内容 Presence — unmountOnHide: true 时非活动面板内容在退出动画后移除;false 时保持挂载但带 hidden 属性;forceMount 将面板保留在 DOM 中,非活动面板仍受 hidden 约束。
  5. 受控与非受控 — 提供了 modelValue 时,内部写入只发出 update:modelValue;DOM 跟随 prop,外部变更自动重新渲染。
  6. 禁用标签 — 禁用触发器仅保留 roving focus 所需的可聚焦性(data-disabled,非原生 disabled 属性),以便方向键跳过;mousedown 与键盘激活被阻止。
  7. ARIA id — 触发器与面板通过确定性 id 关联(soybean-tabs-trigger-{value} / soybean-tabs-content-{value});aria-controls 仅在对应面板注册自身后输出。

FAQ

如何从自动激活切换到手动激活?

设置 activationMode="manual"。手动模式下聚焦标签不再激活;用户通过点击或按 Enter/Space 激活。这符合面板渲染较慢场景下的 WAI-ARIA 标签页模式。

为什么指示器没有立即出现?

指示器需要对活动触发器进行首次测量(偏移 + 尺寸)。它在列表元素挂载或值变化后立即渲染。真实浏览器中 ResizeObserver 通知也会触发重新测量,保证尺寸变化时保持对齐。

unmountOnHide 控制什么?

true(默认)时,切换标签会在退出动画后从 DOM 移除非活动面板内容——利于性能。false 时所有面板保持挂载,但非活动面板带 hidden——利于保留状态(滚动位置、表单输入)。

键盘导航是如何处理的?

列表是 roving-focus 组:ArrowLeft/ArrowRight(垂直模式为 ArrowUp/ArrowDown)移动焦点,Home/End 跳到第一个/最后一个标签,禁用标签被跳过,Enter/Space 激活聚焦的标签。

能完全自定义标签渲染吗?

可以——trigger 插槽接收 scoped { ...item, active },content 插槽接收 { ...item, active },indicator 替换指示器内容。如需完全自定义结构,可从 @vean/aria/tabs 组合 TabsRoot / TabsList / TabsTrigger / TabsContent / TabsIndicator,并通过 provideTabsUi(或 STabs 的 ui prop)注入样式。

需要自己接线 aria-controls 吗?

不需要。每个触发器在面板挂载后自动将 aria-controls 指向其面板 id(soybean-tabs-content-{value}),每个面板也通过 aria-labelledby 指回触发器——条目增删时两者保持同步。

更新日志

版本记录按发布版本分组,便于快速查看这个组件在不同版本里的实际变更。

v0.50.0

2026-10-02

对比版本

样式

为页面标签页添加 size 属性并调整样式

范围: tabs作者: soybeanjs查看提交c6aee

优化

为页面标签页添加 size 属性并调整样式

范围: tabs作者: soybeanjs查看提交c6aee

v0.8.0

2026-02-10

对比版本

新功能

为动态内容管理添加 registerContentId 和 unregisterContentId

范围: tabs作者: soybeanjs查看提交c58fa

v0.5.3

2026-02-05

对比版本

修复

将 nextTick 添加到 watchEffect 以获取 dom

范围: tabs作者: soybeanjs查看提交00dcd

v0.0.2

2025-11-18

对比版本

新功能

引入具有可自定义样式和功能的选项卡组件,包括水平、垂直和填充选项

范围: tabs作者: soybeanjs查看提交c407c

样式

将 theme 变量重命名为 themeContext,以确保各标签页组件间的一致性

范围: tabs作者: soybeanjs查看提交084e8

新功能

引入具有可自定义样式和功能的选项卡组件,包括水平、垂直和填充选项

范围: tabs作者: soybeanjs查看提交c407c

样式

将 theme 变量重命名为 themeContext,以确保各标签页组件间的一致性

范围: tabs作者: soybeanjs查看提交084e8