Steph Huynh

Primitives / Tag

Tag.

Tag is a read-only pill for skills, stacks, and topics. It replaces one-off rounded-full spans on the about teaser, work index, posts, and selected-work cards.

How the primitive behaves

Tag renders a span with token-based border and fill. Variants are implemented with tailwind-variants so new surfaces can share tagVariants without copying class strings.

Source of truth

Custom primitive in system/primitives/tag. Exported from $lib/system.

Open in Storybook →

Primitive roles

Skill chip

Neutral outline pills for grouped skills on the homepage about teaser.

Topic label

Muted fill tags on project and post cards for stack or category metadata.

Filter affordance

Read-only labels today; same styles if interactive filters are added later.

Anatomy

outline

SvelteTypeScriptDesign systems

muted (default)

SvelteTypeScriptDesign systems

Variant

outline uses border only; muted adds bg-muted for slightly stronger contrast on cards.

Shape

Rounded-full pill with text-xs and muted-foreground label color.

Children

Short text only. Keep labels concise so wraps stay even in flex groups.

Guidelines

  • Import Tag from $lib/system. Do not recreate rounded-full border spans in route files.
  • Use variant="outline" for dense skill lists; default muted for card tag rows.
  • Wrap tags in flex flex-wrap gap-2 (or gap-1.5 for tight skill groups).
  • Tags are not buttons. If a tag becomes clickable, use a button or link with explicit semantics.
  • Do not use Tag for status (Live, Open to work). Use LiveBadge or StatusIndicator instead.

In practice

Homepage skills?

variant="outline" inside gap-1.5 flex wrap.

Project card metadata?

Default muted variant in gap-2 flex wrap.

Green availability?

StatusIndicator, not Tag.

Nav “Live” pill?

LiveBadge.

Related primitives

Other primitives in the system, in the same order as the documentation sidebar.