定价

Tab 使用手册

v1.3.2 · @snowui-design-system/components

许可阅读:首次阅读组件文档、源码或 npm 使用流程,先读完整 LICENSE;同任务同版本去重。公开 API 配置与内部实现修改分别按许可处理;全部组件使用统一运行包,源码权益以许可为准。

组件介绍

在同一区域的多个视图或内容面板之间切换,支持数据生成或自定义按钮组合,并提供键盘导航。

使用选择

用于同一区域的内容面板或视图切换;截图中的下划线标签页可选 underline 变体。只改变过滤参数时使用 Segmented。

  • items 提供唯一 value 与 label;显式 Button as="item" 替换 items。

  • bind:value 同步当前项;缺失或不匹配时仅视觉回退,不写回值。内容面板按当前值由页面展示。

快速开始

以下示例展示推荐的基本组合。更多场景与组合限制见后文。

<script lang="ts">	import { Tab } from '@snowui-design-system/components';</script> <Tab itemRole="tab" size="lg" value="preview" aria-label="Component example view" items={[{ value: 'preview', label: 'Preview' }, { value: 'code', label: 'Code' }, { value: 'api', label: 'API' }]} />

API

关键字 类型 默认值 描述
value string — 当前激活项的唯一值,支持 bind:value;点击或键盘激活时更新。缺失或不匹配时视觉回退到首个可用项,不自动写回绑定值。
variant TabVariant "pill" Tab 视觉变体
size TabSize "sm" 同时控制 Tab 容器的 padding / radius / gap,并作为组合默认值传给直系 Button as="item";Item 尺寸样式优先级为 style > class > Button size > Tab size
row boolean false 显式横向排列;row 与 column 均为 false 时仍横向显示,同时启用时 row 优先。
column boolean false 纵向排列;与 Frame 写法统一
fill boolean false Figma fill 宽度;容器有显式宽度时,横向子项等宽填满
onChange (value: string) => void — 用户激活不同选项后调用,参数为新 value;重复激活当前项不触发,回调不可取消选择。
selectionFollowsFocus boolean false 方向键是否直接激活;Tab 默认 false(仅切焦点 + Enter 激活),Segmented 默认 true
role string "tablist" ARIA 容器 role
itemRole string — 写入子项的 ARIA role;未传时保留 Button 自身语义。选项卡示例显式传 tab;传 radio 时同步 aria-checked,其余情况同步 aria-selected。
children Snippet — 无参数的显式子项内容,使用 Button as="item" 并设置唯一 value;替代 items,子项 Props 直接配置。
items TabItem[] [] 内置子项数据,每项必填唯一 value 和可读 label,可选 icon 组件及 disabled;icon 生成 Icon + Text,禁用项跳过键盘选择。children 存在时忽略 items。
parts ComponentPartsOf<{ Button: typeof Button; Icon: typeof Icon; Text: typeof Text; }> — 批量配置默认生成的 Button、Icon 与 Text,例如 parts.Button.scaleOnHover;显式 children 不消费这些默认子项配置。

未重新声明的继承能力请查所属基础组件文档;本表只列本组件源码具名公开属性。

使用边界与详细说明

默认内置模式 / 显式组合模式

  • 默认内置模式(推荐):items 自动生成 <Button as="item">;item 可用 icon 声明图标,Tab 内置生成 Icon + Text,适用于 icon-toggle;parts.Button / parts.Icon / parts.Text 配置统一 Props。

  • 显式组合模式:显式书写 Button,用于 Icon、Text、复杂内容或逐项 Props 差异。


设计原则

  • 子项即 Button:不新增 TabItem 组件。子项直接使用 Button,在 Button 上声明 value="..." 即可。Button 的 size 档位决定 Item 的 padding / radius / font-size / line-height(完全继承 Button SM/MD/LG)。

  • 容器接管激活态视觉:Tab 不修改 Button 源码,而是通过 CSS 上下文 override Button 的三层桥接变量(--snowui-button-background-override / --snowui-button-color-override / --snowui-button-opacity-override / --snowui-button-padding-override)在 Tab 上下文内接管视觉,不污染外部 Button。

  • 共享 indicator FLIP 动效:激活态的"白底"/"灰底"/"下划线"通过一个共享的 .snowui-tab-indicator 元素绝对定位,在 Item 间通过 transform/width/height 平滑过渡,而非每个 Item 各自 fade。

  • 复合控件 hover:Item 默认关闭 Button 的 scale hover,保留 Tab 自己的背景/透明度反馈与 indicator;子 Button 或 parts.Button.scaleOnHover=true 可显式重新开启。


2.2 子项约定

子项必须是 <Button as="item">,在 Button 上声明:

  • value="xxx" —— 必填,项标识值(通过 Button rest-spread 落到根 <button> 元素的 value 属性)

  • 可选 disabled —— 禁用单项

  • 可选 href —— 通过 Button 的 href 实现路由型 Tab(Button 会渲染为 <a>)

  • 可选 bare —— 使用无 padding / radius / 背景且不限制内容类型的 Button;Tab 继续通过 Button 根节点上的 --snowui-button-opacity-override 独立接管 inactive / hover / active 透明度,因此不依赖 Button bare 的默认强调级别

variant="pill"(样式1, 默认)

容器有 --black-4 背景 + padding,并使用与 SearchBox 一致的 blur(1.25rem)(20px)背景模糊。激活项:--static-white-80 白底 + 0 2px 4px rgba(0,0,0,0.1) shadow。未激活项 Text / Icon 使用 --black-100 × opacity: 0.4;激活项 Text / Icon 使用 --static-black-100 与 opacity: 1;未激活项 hover 时仅将 opacity 提升到 1。

variant="solid"(样式2)

容器无背景、无 padding。激活项:--black-4 背景,无 shadow。激活项 Text / Icon 保持 Button 默认颜色链;未激活项 Text / Icon 使用 --black-100 × opacity: 0.4。

variant="underline"(样式3)

容器无背景、无圆角。子项 padding 0(override Button)。激活项底部 2px 横向下划线(垂直时为左侧 2px 竖线),颜色 --primary;激活项 Text / Icon 同样使用 --primary。未激活项 Text / Icon 使用 --black-100 × opacity: 0.4。子项间距更大:SM=--gap-3(12) / MD=--gap-4(16) / LG=--gap-5(20)。

variant="icon-toggle"(样式4)

容器视觉与 pill 相同,包含与 SearchBox 一致的 blur(1.25rem)(20px)背景模糊。未激活项隐藏 .snowui-text,只显示图标(子项内部需包含 Icon + Text 节点);激活项显示 icon + text,文字渐显时消费 Frame 生命周期进入 bridge 时序,宽度通过 Frame size motion bridge 平滑展开。

默认items模式在icon-toggle中使用每项label作为可访问名称,文字隐藏时仍可识别;显式children模式由调用方给每个Button提供aria-label。内部图文间距复用Button所有者,不给每个控件外包Frame。

variant="bare"

容器无背景、padding 和圆角,不显示 indicator;Item 无背景、padding 和圆角,只通过 opacity: 0.4 -> 1 表达未激活、hover 与激活状态。内容可以是文字、单 Icon 或 Icon + 文字。Item gap 复用 underline 的尺寸梯度:SM=12px / MD=16px / LG=20px。


动效

Item 颜色、透明度继续消费 Frame 默认动效系统。Tab 根注入 TAB_INDICATOR_MOTION_STYLE;共享 indicator 的位移消费 Frame control bridge,宽高变化消费 Frame size bridge,两者统一使用 Tab indicator preset。icon-toggle 因文字显隐触发的重测也保持动效,不再被 ResizeObserver 瞬间贴位覆盖。

场景 实现 bridge 变量
激活 indicator 位移 共享 indicator 元素 transform: translate(x, y) 过渡 --snowui-frame-control-motion-*(TAB_INDICATOR_MOTION)
激活 indicator 尺寸变化 width/height 过渡 --snowui-frame-size-motion-*(TAB_INDICATOR_MOTION)
inactive / hover / active 前景切换 opacity 过渡(Button opacity override) --snowui-frame-color-motion-*(fallback 0.15s ease-out)
icon-toggle 宽度展开 Item width 过渡 --snowui-frame-size-motion-*
icon-toggle 文字渐显 Text opacity 过渡 --snowui-frame-appear-motion-*(生命周期进入时序桥接变量)
underline 移动 同 indicator,仅高度固定 2px Frame control / size bridge

Tab indicator 的具体时序以 TAB_INDICATOR_MOTION 为准;TAB_INDICATOR_MOTION_STYLE 将同一 preset 注入 Frame control / size 两组 bridge,禁止分别维护位移和尺寸数值。


布局模型

主布局模型:内联外壳布局(同 Button)。Tab 自身是一个 flex 容器(inline-flex,column 时 flex-direction: column),内部:

  • 第一个 child:绝对定位的 <div class="snowui-tab-indicator">,跟随激活 Button 通过 transform/width/height 过渡

  • 之后是用户传入的 Button 子项;Button position: relative; z-index: 1 确保文字在 indicator 之上

fill={true} 时,横向子项使用 flex: 1 1 0 等宽填满容器可用宽度。通常配合 style="width: ..." / 宽度工具类使用;未定义容器宽度时仍按内容自然宽度布局。

详见 LayoutProtocol.md §12.3(源码参考:specs/maintainers/LayoutProtocol.md)。


键盘行为

  • ← / →(row)或 ↑ / ↓(column):移动焦点。当 selectionFollowsFocus=true(Segmented)时直接激活。

  • Home / End:跳到首/末项,行为同上。

  • Enter / Space:由 Button 原生 click 行为触发,激活当前焦点项。

  • Roving tabindex:激活项 tabindex=0,其他项 tabindex=-1。整个 Tab 在外部 Tab 键序列中只占一位。

使用示例

<script lang="ts">  import { Button, Icon, Text } from '@snowui-design-system/components';  import { Tab } from '@snowui-design-system/components';  import { FourLeafClover, Star } from '@snowui-design-system/resource-svelte';  let value = $state('web');</script>  <Tab bind:value variant="pill" size="sm">  <Button as="item" value="web"><Icon><FourLeafClover /></Icon>Web</Button>  <Button as="item" value="mobile"><Icon><Star /></Icon>Mobile</Button></Tab>  <Tab variant="solid" size="md">  <Button as="item" value="web"><Icon><FourLeafClover /></Icon>Web</Button>  <Button as="item" value="mobile"><Icon><Star /></Icon>Mobile</Button></Tab>  <Tab variant="underline" size="lg">  <Button as="item" value="overview"><Icon><FourLeafClover /></Icon>Overview</Button>  <Button as="item" value="details"><Icon><Star /></Icon>Details</Button></Tab>  <Tab variant="icon-toggle">  <Button as="item" value="web" aria-label="Web"><Icon><FourLeafClover /></Icon><Text>Web</Text></Button>  <Button as="item" value="mobile" aria-label="Mobile"><Icon><Star /></Icon><Text>Mobile</Text></Button></Tab>  <Tab  variant="icon-toggle"  value="web"  items={[    { value: "web", label: "Web", icon: FourLeafClover },    { value: "mobile", label: "Mobile", icon: Star }  ]}/>  <Tab variant="bare" size="md" value="all">  <Button as="item" value="all">All</Button>  <Button as="item" value="random" iconOnly aria-label="收藏"><Icon><Star /></Icon></Button></Tab>  <Tab column variant="underline">  <Button as="item" value="a">A</Button>  <Button as="item" value="b">B</Button></Tab>  <Tab fill style="width: calc(var(--size-20) * 4)" value="web">  <Button as="item" value="web">Web</Button>  <Button as="item" value="mobile">Mobile</Button></Tab>  <Tab variant="bare" value="random">  <Button as="item" value="all">All</Button>  <Button as="item" value="random">Random</Button></Tab>

Tab 样式覆盖

先阅读 完整 LICENSE;同任务、同版本、同范围去重。

优先用组件公开 Props 匹配合适样式,尽可能保留原有视觉。确需改写时按 样式选择与改写顺序 使用自己的 class(含项目已有 Tailwind)或实例 style。以下名称来自源码实际消费的公开 override;先核对目标作用域,不修改私有 DOM。采用 SnowUI Token 时选择正确类别,外部应用不被要求安装一方 utilities。

变量 用途与默认参考
--snowui-button-background-override 背景(默认值见组件源码)
--snowui-button-border-color-override 边框颜色(默认值见组件源码)
--snowui-button-color-override color(默认值见组件源码)
--snowui-button-icon-only-padding-override icon-only 模式 padding(sm=4px md=8px lg=12px)
--snowui-button-opacity-override 不透明度(默认值见组件源码)
--snowui-button-padding-override padding y+x
--snowui-button-radius-override border-radius
--snowui-tab-background-blur-override 容器背景模糊(默认 pill/icon-toggle=1.25rem=20px;其他变体=none)
--snowui-tab-background-override 容器背景(默认 pill/icon-toggle=var(--black-4);solid/underline/bare=transparent)
--snowui-tab-gap-override 容器子项间距(默认 sm=calc(var(--gap-1)/2)=2px;md/lg=var(--gap-1)=4px;underline/bare 时 sm/md/lg=var(--gap-3/4/5)=12/16/20)
--snowui-tab-hover-opacity-override 未激活 item hover 透明度(默认 1)
--snowui-tab-inactive-opacity-override 未激活 item 透明度(默认 0.4)
--snowui-tab-padding-override 容器 padding(默认 sm=calc(var(--padding-1)/2)=2px;md/lg=var(--padding-1)=4px;solid/underline/bare 时为 0)
--snowui-tab-radius-override 容器 radius(默认 sm=var(--radius-4)=16;md=var(--radius-5)=20;lg=var(--radius-6)=24;underline/bare=0)

设计指南 · Token · 组合边界

Tab 类型与状态

必填属性:无具名必填属性。

可双向绑定:bind:value。

继承声明:Omit<FrameProps, "children" | "value">。继承能力以基类公开文档为准;Omit 中的字段已排除,不能按基类原样使用。

共享 Frame API · 返回 API

以下为公开属性实际引用的类型声明,来自源码;Svelte Snippet 表示内容片段,ComponentProps 表示对应组件的 Props。

TabVariant

来源:components/src/components/Tab.svelte

export type TabVariant = "pill" | "solid" | "underline" | "icon-toggle" | "bare";

TabSize

来源:components/src/components/Tab.svelte

export type TabSize = "sm" | "md" | "lg";

TabItem

来源:components/src/components/Tab.svelte

export interface TabItem {        value: string;        label: string;        icon?: Component;        disabled?: boolean;    }

ComponentPartsOf

来源:components/src/logic/component-parts.svelte.ts

export type ComponentPartsOf<    T extends Record<string, Component<any>>,> = {    [K in keyof T]?: ConfigurableComponentPartProps<T[K]>;};

ConfigurableComponentPartProps

来源:components/src/logic/component-parts.svelte.ts

export type ConfigurableComponentPartProps<C extends Component<any>> = Partial<    Omit<ComponentProps<C>, ComponentPartControlledKey>>;

ComponentPartControlledKey

来源:components/src/logic/component-parts.svelte.ts

export type ComponentPartControlledKey =    | "children"    | "as"    | "value"    | "defaultValue"    | "open"    | "selected"    | "checked"    | "disabled"    | "readonly"    | "id"    | `on${string}`    | `aria-${string}`;