f-ui
Design

Tag Selection

Mandatory rules for Status Tag, Label Tag, shadcn Badge, and filter chips — read-only display vs interactive pills.

Use this page as the single source of truth when choosing a pill-shaped UI element. There is no “use whatever looks nice” path.

Three Principles

  1. Read-only display (user cannot click or remove) → only Status Tag or Label Tag.
  2. Interactive (select, remove, navigate) → only shadcn Badge inside controls, or Data Table filter chips — never Label Tag.
  3. Numeric overlay on an icon or avatar (unread count) → future Count Badge; do not fake it with Tag or Badge text.

Decision Tree

Where does this pill appear?

├─ Table cell or detail field showing a stored value?
│   ├─ Good/bad/urgent/processing semantics? → StatusTag (schema kind: "status")
│   └─ Category, role, channel, type?        → LabelTag (schema kind: "label")

├─ Inside an input (Multi-Select selected items)?
│   └─ shadcn Badge (removable chip) — do not use LabelTag

├─ Active filter with remove (×) on the filter bar?
│   └─ DataTableFilterBar chip — do not hand-roll Badge or LabelTag

└─ Unread count on Bell / avatar?
    └─ Not implemented yet — avoid Tag; use CountBadge when available

Scenario Matrix

ScenarioComponentNotes
Order status, payment, priorityStatus Tagkind: "status", StatusVariantMap with tone
In progress with spinnerStatus Tagicon: "spin" on that variant only
Completed / failed with iconStatus Tagicon: "auto" — opt-in, not table default
Category, channel, role, typeLabel Tagkind: "label", LabelVariantMap; default neutral
Dense table columnsStatus / Label TagOmit icon unless the state needs emphasis
Multi-Select selected optionshadcn BadgeFull pill, removable — component-internal
Filter bar active conditionFilter bar chipPart of data-table filter surfaces
Detail page role (read-only)Label TagSame as users table — not shadcn Badge
Marketing / link pillshadcn BadgeasChild + link OK; not for table enums
Sidebar unread 3Count Badge (future)Not Tag

Status Tag vs Label Tag

QuestionYes →No →
Should the user care if the value is good, bad, or urgent?Status TagLabel Tag
Can you use success / warning / destructive?Status onlyNever on labels
Spinner while waiting?icon: "spin" on StatusLabels do not spin

Schema:

  • StatusVariantMap: { label, tone, icon? }tone required.
  • LabelVariantMap: { label, accent? } — no tone; optional accent: "auto".

See Data Table — Status Tag and formatters.

Label Tag vs shadcn Badge

Both can look like small capsules. They are not interchangeable.

Label Tagshadcn Badge
JobShow a field valuePart of a control (selection, link)
Shaperounded-md + visible borderrounded-4xl pill
InteractionStaticOften removable / clickable
ColorNon-semantic accent or neutralprimary, secondary, outline, …
Import@/components/f-ui/label-tag@/components/ui/badge

Visual rule of thumb: bordered, squarer, in a table cell → data tag. Full pill inside an input with × → shadcn Badge.

Do not display the same field two ways (e.g. Label Tag in the table and Badge on the detail page for role).

What We Do Not Ship

ComponentWhy
f-ui Badge for status/labelsOverlaps Status Tag / Label Tag; confuses variant vs tone
Label Tag for filtersUse filter bar or Multi-Select
shadcn Badge for table status/category columnsUse schema kind: "status" / "label"

Code Review Checklist

  • Table/detail enum uses kind: "status" or kind: "label", not legacy badge.
  • No import { Badge } from "@/components/ui/badge" for read-only status, category, or role.
  • Label fields do not use semantic status tones.
  • Processing states use icon: "spin" only where the value is truly in-flight.
  • Same field uses the same tag component on list and detail views.

On this page