定价

Tag 使用手册

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

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

组件介绍

以可交互标签表达标记、筛选条件或路径片段,适合组织内容与收敛选择范围。

使用选择

用于带边界的标签内容及公开的关闭操作。关闭和选中是不同语义;需要独立按钮或选择控件时使用对应组件。

  • closable 显示关闭操作,onClose 通知页面移除数据;关闭不会替页面修改列表。

  • variant、shape 和 toggle 分别控制外观、形状与切换能力;parts 仅配置默认关闭按钮。

  • 内置关闭按钮名称随LocaleProvider更新,可用Provider messages覆盖;标签内容与关闭后移除责任仍由调用方负责。

快速开始

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

<script lang="ts">	import { Tag, Button, Frame, ScrollArea } from '@snowui-design-system/components';</script> <ScrollArea axis="horizontal" horizontalTrackPosition="viewport" style="max-width: 100%;"><Frame singleLine gap={3} width="max-content" minWidth="100%" class="justify-center">	<Tag toggle>Design</Tag>	<Tag toggle>Engineering</Tag>	<Tag toggle>Product</Tag></Frame></ScrollArea>

API

关键字 类型 默认值 描述
parts ComponentPartsOf<{ Button: typeof Button }> — 配置组件生成的关闭 Button;不影响显式 children 内的按钮。
variant "default" | "active" "default" 视觉变体。default = Black/4% 背景;active = Brand 10% 背景 + Brand 文字
toggle boolean false Toggle 模式语法糖。内部自动注入 Click={{ Idle: "Active", Active: "Idle" }} 与 whileClick=false;Active 状态由 Frame 输出的 data-state="Active" 触发 Brand 激活态;aria-pressed 自动输出。消费方可继续传 Click / whileClick 显式覆盖。
closable boolean false 是否显示内置删除 X(hover Tag 时显形)
shape "default" | "left-arrow" | "right-arrow" "default" 外壳形状,用于路径 / 面包屑片段
onClose (event: MouseEvent) => void — 点击 X 时回调(不直接销毁 Tag,移除逻辑由消费方决定)
children Snippet — 标签显示内容,由 Frame 的 children 渲染协议承接;关闭按钮由组件另行管理。

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

使用边界与详细说明

设计形态

设计稿中的 Tag 形态统一收敛为以下能力组合:

形态 组件表达 说明
Tag <Tag>Label</Tag> 仅文字
Tag × <Tag closable>Label</Tag> 文字 + 内置关闭 X
● Tag 外部 <Icon as="leading"> + Tag 左侧 Dot 不内置,由消费方显式传入
● Tag × 外部 leading Icon + closable Icon、文字、X 走同一内联外壳布局
品牌色 ● Tag × variant="active" 或 toggle 切到 Active Brand 激活态
< Tag shape="left-arrow" 路径 / 面包屑片段
Tag > shape="right-arrow" 路径 / 面包屑片段

设计稿中的左侧 Dot 仅作组合展示,Tag 不内置 leading Icon;X 由 closable 内置提供。设计稿内 X 与文字紧贴,组件默认 gap=0,外部覆盖 --snowui-tag-gap 或传 gap 时会同步影响 Icon、文字与 X 的间距。

与 Chip / Badge 的区分

维度 Tag Chip Badge
内置 leading Dot 否 是 —
删除 X 内置(closable) 否 —
激活态 内置(variant="active") 否(外部 class 控制颜色) —
箭头外壳 内置(shape) 否 —
尺寸档位 单一尺寸 sm / lg 多档
主要语义 用户标记 / 筛选 / 路径片段 状态 / 分类展示 数字 / 圆点徽标
布局 内联外壳(同 Button) 三槽位 内联外壳

组件特有属性 (Component-Specific Props)

不提供 size 属性:设计稿只有单一尺寸。

关键字 (Keyword)

关键字 类型 默认值 描述
as 'leading' | 'trailing' - 角色化:作为外部容器(Field 等)的槽位

布局模型

主布局模型:内联外壳布局(与 Button 一致)。定义见 ../../../specs/maintainers/LayoutProtocol.md §12.4(源码参考:specs/maintainers/LayoutProtocol.md)。

  • 子元素通过 gap 自然排列;外部覆盖 --snowui-tag-gap 或传 gap 即可同步影响所有子元素间距(包括内置 X 与文字、外部 Icon 与文字)。

  • 不内置 leading Icon;需要 Dot 由消费方显式传入 <Icon as="leading">。

  • 删除 X 由 closable={true} 自动渲染在末尾;视觉与 hover 复用 Button bare emphasis="muted"(默认图标为 Components 自有语义 close,其包内形状快照来源为 close-regular.svg);默认 width: 0、min-width: 0 不占位,hover Tag 时显形,hover X 自身时透明度提升到 1。激活态下 X 颜色源切到 Brand:未 hover X 时 40%,hover X 时 100%。

  • 边距按元素类型决定(与 Figma 对齐):文字与边的间距 8px、Icon / X 与边的间距 4px。组件通过 MutationObserver 检测真实首/末位节点(包含文本节点),按节点类型写到 data-edge-left / data-edge-right("icon" / "text"),CSS [data-edge-*="icon"] 把对应侧 padding 从 8px 收紧到 4px。纯 CSS :first-child / :last-child 只看元素节点,无法识别"末位文字"的情况,因此走 JS。closable 的 X 不计入边距检测(X 由 [data-closable]:hover 单独管理右 padding)。

  • 箭头形状(left-arrow / right-arrow)由内部 SVG 背景路径实现,不进入子元素布局;组件用 ResizeObserver 获取当前宽高并生成完整外轮廓,所有拐点都通过二次贝塞尔圆角化,尽量复原 Workshop node-id=11951-40471。

无障碍 (Accessibility)

与 Button 一致,自动输出 aria-pressed:

  • 当 variant="active"(映射到 currentState="Active")或通过 toggle / Click={{ Idle: "Active", Active: "Idle" }} 切到 Active 时,根节点输出 aria-pressed="true";处于 Idle 时输出 aria-pressed="false"。

  • 消费方显式传入 aria-pressed 或 aria-selected 时外部值优先,用于列表选择语境改用 aria-selected。

  • 删除 X 渲染为真实 button type="button",内置名称随LocaleProvider更新(默认简中“关闭标签”、英文“Close tag”),键盘可达。

  • 删除 X 点击时组件内部会 stopPropagation(),避免误触 Tag 根节点的 onclick;移除逻辑仍由消费方在 onClose 中决定。

布局变量链

变量 默认值 用途
--snowui-tag-padding-block calc(var(--padding-1, 4px) / 2)(= 2px) 外壳纵向内边距
--snowui-tag-padding-inline var(--padding-2, 8px) 外壳横向内边距
--snowui-tag-padding-inline-leading var(--padding-1, 4px) 含 leading 子节点时左侧 padding
--snowui-tag-padding-inline-trailing var(--padding-1, 4px) 含 trailing(X)时右侧 padding
--snowui-tag-gap 0 子元素间距;可被外部 gap 覆盖
--snowui-tag-radius var(--radius-3, 8px);箭头形状由 SVG path 内部圆角控制 外壳圆角
--snowui-tag-font-size var(--text-12, 12px) 文字字号
--snowui-tag-line-height var(--leading-12, 16px) 文字行高
--snowui-button-icon-size var(--size-4)(标准根字号16px) 内置 X 尺寸
--snowui-tag-bg var(--black-4, rgba(0,0,0,0.04)) 背景
--snowui-tag-color inherit 文字颜色

用法示例

 <Tag>Label</Tag>  <Tag closable onClose={() => remove('foo')}>Label</Tag>  <Tag>    <Icon as="leading"><DotCircle Weight="fill" /></Icon>    Label</Tag>  <Tag variant="active" closable>    <Icon as="leading"><DotCircle Weight="fill" /></Icon>    Filtered</Tag>  <Tag toggle>Filter</Tag>  <Tag closable style="--snowui-tag-gap: 4px;">    <Icon as="leading"><DotCircle Weight="fill" /></Icon>    Label</Tag>  <Tag shape="right-arrow">Home</Tag><Tag shape="left-arrow">Settings</Tag>  <Tag shape="right-arrow" closable>Filters</Tag>  <Tag whileClick={false} Click={{ Idle: "Active", Active: "Idle" }}>    Label</Tag>  <Tag aria-selected={isSelected} variant={isSelected ? "active" : "default"}>    Label</Tag>

Tag 样式覆盖

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

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

变量 用途与默认参考
--snowui-button-color-override color(默认值见组件源码)
--snowui-button-opacity-override 不透明度(默认值见组件源码)
--snowui-tag-bg-override 背景(默认 var(--black-4);active 时 var(--brand) 10%)
--snowui-tag-color-override color(默认 inherit;active 时 var(--brand))
--snowui-tag-font-size-override font-size(默认 var(--text-12))
--snowui-tag-gap-override 子元素间距(默认 0;覆盖后同步影响 Icon 与文字、X 与文字)
--snowui-tag-line-height-override line-height(默认 var(--leading-12))
--snowui-tag-padding-override padding y+x(默认 calc(--padding-1 / 2) var(--padding-2) = 2px 8px)
--snowui-tag-radius-override border-radius(默认 var(--radius-3)=8px;箭头形状 4px)

设计指南 · Token · 组合边界

Tag 类型与状态

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

可双向绑定:本组件未声明具名双向绑定属性;状态更新通过公开回调或所属宿主处理。

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

共享 Frame API · 返回 API

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

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}`;