Pricing

Tag handbook

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

License: Before first reading component documentation, source code, or npm usage instructions, read the complete LICENSE. One review covers the same task and version. Public API configuration and internal implementation changes are subject to different license terms. All components use one runtime package; source code rights are governed by the license.

Overview

Use interactive tags for labels, filters, or path segments to organize content and narrow a selection.

When to use it

Use Tag for bounded label content and its public close action. Closing and selection have different meanings; use a dedicated button or selection control when needed.

  • closable shows the close action, and onClose tells the page to remove the data. Closing does not change the page’s list automatically.

  • variant, shape, and toggle control appearance, shape, and toggle behavior. parts configures only the generated close button.

  • The built-in close button name follows LocaleProvider and supports Provider messages overrides. The caller still owns tag content and removal after onClose.

Quick start

This example shows the recommended basic composition. See the following sections for more scenarios and composition limits.

<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

Keyword Type Default Description
parts ComponentPartsOf<{ Button: typeof Button }> — Configure the generated close Button without affecting buttons explicitly supplied in children.
variant "default" | "active" "default" Visual variant. default = Black/4% background; active = Brand 10% background + Brand text
toggle boolean false Shorthand for toggle mode. Internally injects Click={{ Idle: "Active", Active: "Idle" }} and whileClick=false. Frame’s data-state="Active" triggers the Brand active style, and aria-pressed is emitted automatically. Consumers can explicitly override Click and whileClick.
closable boolean false Show the built-in close X, which becomes visible on Tag hover.
shape "default" | "left-arrow" | "right-arrow" "default" Shell shape, used for path / breadcrumb fragment
onClose (event: MouseEvent) => void — Called when X is clicked. Tag is not destroyed automatically; the consumer decides how to remove it.
children Snippet — The label display content is undertaken by the children rendering protocol of Frame; the close button is managed separately by the component.

See the base component documentation for inherited capabilities not redeclared here. This table lists only the named public props declared in this component’s source.

Usage boundaries and details

Design forms

The Tag forms in the design are composed from these capabilities:

Form Component composition Description
Tag <Tag>Label</Tag> Text only
Tag × <Tag closable>Label</Tag> Text with built-in close X
● Tag External <Icon as="leading"> + Tag The leading dot is not built in; consumers add it explicitly.
● Tag × External leading Icon + closable Icon, text, X follow the same inline shell layout
Brand color ● Tag × variant="active" or toggle switches to Active. Brand activation state
< Tag shape="left-arrow" Path / Breadcrumb fragment
Tag > shape="right-arrow" Path / Breadcrumb fragment

The leading dot in the design is composition only; Tag has no built-in leading Icon. closable supplies X. X touches the text in the design, so the default gap is 0. Overriding --snowui-tag-gap or passing gap changes spacing among Icon, text, and X together.

Tag compared with Chip and Badge

Dimension Tag Chip Badge
Built-in leading dot No Yes —
Close X Built-in (closable) No —
Active state Built-in (variant="active") No (external class controls color) —
Arrow shell Built-in (shape) No —
Size options Single size sm / lg Multiple sizes
Primary purpose User label / filter / path segment Status / Classification Display Count / dot badge
Layout Inline shell (same as Button) Three slots Inline shell

Component-specific props

No size prop: the design has one size.

Keywords

Keyword Type Default Description
as 'leading' | 'trailing' - Role as a slot in an external container such as Field.

Layout model

Main layout model: inline shell (as in Button). See specs/maintainers/LayoutProtocol.md §12.4.

  • Children are laid out with gap. Override --snowui-tag-gap or pass gap to change spacing among all children, including the built-in X and text or an external Icon and text.

  • No built-in leading Icon; consumers add a dot explicitly with <Icon as="leading">.

  • closable={true} renders X at the end. Its visuals and hover use Button bare emphasis="muted" (the default icon is Components’ semantic close, whose packaged shape snapshot comes from close-regular.svg). It occupies no space by default (width: 0; min-width: 0), appears when Tag is hovered, and reaches full opacity when X itself is hovered. In the active state, X uses Brand at 40% opacity, rising to 100% on X hover.

  • Padding depends on edge content (matching Figma): text has 8px from the edge; Icon/X has 4px. A MutationObserver checks the actual first and last nodes, including text nodes, and sets data-edge-left / data-edge-right to "icon" or "text". CSS [data-edge-*="icon"] reduces the relevant side from 8px to 4px. CSS :first-child / :last-child sees elements only, so it cannot detect trailing text. The generated X is excluded from edge detection; [data-closable]:hover separately controls right padding.

  • Arrow shapes (left-arrow / right-arrow) use a private SVG background path outside child layout. ResizeObserver reads current width and height to generate the full outline, rounding every corner with quadratic Bézier curves to approximate Workshop node-id=11951-40471.

Accessibility

Consistent with Button, automatically output aria-pressed:

  • When variant="active" maps to currentState="Active", or toggle / Click={{ Idle: "Active", Active: "Idle" }} switches to Active, the root emits aria-pressed="true"; in Idle it emits aria-pressed="false".

  • Explicit consumer aria-pressed or aria-selected values take precedence. Use aria-selected in list selection contexts.

  • The close X is a real button with type="button". Its built-in name follows LocaleProvider (default Chinese or English "Close tag"); it remains keyboard accessible.

  • Clicking X calls stopPropagation() so it does not trigger the Tag root’s onclick. The consumer still decides removal in onClose.

Layout variable chain

Variable Default Use
--snowui-tag-padding-block calc(var(--padding-1, 4px) / 2)(= 2px) Vertical shell padding
--snowui-tag-padding-inline var(--padding-2, 8px) Horizontal shell padding
--snowui-tag-padding-inline-leading var(--padding-1, 4px) Left padding when containing leading sub-nodes
--snowui-tag-padding-inline-trailing var(--padding-1, 4px) Padding on the right side when including trailing (X)
--snowui-tag-gap 0 Child spacing; externally overridable with gap
--snowui-tag-radius var(--radius-3, 8px); the arrow shape is controlled by the internal rounded corners of SVG path Rounded corners of the shell
--snowui-tag-font-size var(--text-12, 12px) Font size
--snowui-tag-line-height var(--leading-12, 16px) Text line height
--snowui-button-icon-size var(--size-4) (standard root size 16px) Built-in X size
--snowui-tag-bg var(--black-4, rgba(0,0,0,0.04)) Backdrop
--snowui-tag-color inherit Text color

Usage examples

 <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 style overlay

Read the complete LICENSE first; one review covers the same task, version, and scope.

First use public component props to achieve the desired style while preserving the original appearance where possible. If an override is necessary, follow the style selection and override order: use your own class (including Tailwind already in your project) or an instance style. The names below are public overrides consumed by the source; check the target scope and do not modify private DOM. Choose the appropriate SnowUI token category. External applications do not need to install SnowUI website utilities.

Variable Purpose and default reference
--snowui-button-color-override Color (see the component source code for the default value)
--snowui-button-opacity-override Opacity (see the component source code for the default value)
--snowui-tag-bg-override Background (default var(--black-4); active var(--brand) 10%)
--snowui-tag-color-override Color (default inherit; var(--brand) when active)
--snowui-tag-font-size-override Font-size (default var(--text-12))
--snowui-tag-gap-override Child spacing (default 0; overrides affect Icon/text and X/text together).
--snowui-tag-line-height-override Line-height (default var(--leading-12))
--snowui-tag-padding-override Padding y+x (default calc(--padding-1 / 2) var(--padding-2) = 2px 8px)
--snowui-tag-radius-override Border-radius (default var(--radius-3)=8px; arrow shape 4px)

Design Guide · Token · Combination boundary

Tag type and status

Required props: no named required props.

Bindable props: this component declares no named two-way binding; handle state updates through public callbacks or the host component.

Inheritance: Omit<FrameProps, "size">. Consult the public Frame documentation; omitted fields cannot be passed through unchanged.

Shared Frame API · Back to API

The following source type declarations are referenced by public props. Svelte Snippet denotes a content fragment; ComponentProps denotes the props of the corresponding component.

ComponentPartsOf

Source: components/src/logic/component-parts.svelte.ts

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

ConfigurableComponentPartProps

Source: components/src/logic/component-parts.svelte.ts

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

ComponentPartControlledKey

Source: components/src/logic/component-parts.svelte.ts

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