A Tag states a descriptive fact about a record: which client it belongs to, which environment it runs in, what type of file it is, what role a person holds. It has no border and no status colour, and a leading icon names the kind of fact, so a row of tags reads as attributes and never as states or selections.
It is the fourth of the kit's small-label species. StatusPill says how a record is doing, Chip says what is selected, FieldChip names a data field or file, and Tag describes the record.
When to reach for it#
A fact that is not a state, not a selection and not a name: the client, the environment, the file type, the role. If the reader would ask "is that good or bad?", it is a status and belongs in StatusPill. If it can be switched on or off, it is a Chip.
Contract#
children(required): the fact, as short text.Icon: the leading icon that names the kind of fact (a team for a client, a server for an environment). It takes the usual icon props (iconSize,iconProps,iconClassName). Pass one; an icon-less tag reads as an unlabelled grey pill.size:sm(default, 20px high) ormd(24px).onClick: makes the tag a real button, for filtering by the fact. It gains a hover wash and a focus ring, never a border. Without it the tag is a plain span.tooltip: hover text. With none, a label that is cut shows its full text.className.
The label truncates with an ellipsis inside a narrow box, and the full text appears on hover only when something is hidden.
Laws it enforces#
- Fit, then truncate, never clip. A cut label ends in an ellipsis and carries its full text on hover.
- Show only what has something to say. The tooltip appears only when text is hidden.
- One signal, said once. The icon names the kind of fact, so the tag never repeats it in words ("Client: Walmart" is just "Walmart" with a team icon).
Sanctioned combinations#
| Combination | What it produces | Why |
|---|---|---|
Tag Icon="Team" with the client name | A descriptive label in a row or card header | The icon names the fact, so no field label is needed |
Tag onClick inside a table cell | A fact that filters the list when clicked | A real button with a hover wash, no border |
| A few tags in a wrapping flex row | The attributes of one record | Tags are neutral and equal, so order carries no meaning |
Banned combinations#
Do not use a Tag for state. A job that is running or failed is a StatusPill; a tag has no status colour on purpose.
Do not use a Tag for a selection or a filter that is applied. That is a Chip, which can be toggled and removed.
Do not draw a border or a coloured fill on a tag with className. A bordered tag reads as a button or a status.
Do not put a status word in a tag to avoid the pill. If a filter needs the same word as a table pill, both read one defineStatusMap.
Before you adopt this#
- Does the page already show this fact in a header or column title? Then a tag repeats it.
- Is it a state, a selection or a name? Then it is a
StatusPill, aChipor aFieldChip. - Does the kit pin your app uses include
Tag? It arrives with the kit release after 0.3.0. - Is the fact clickable? Pass
onClickfor the filter, and give the table column a facet so the filter has somewhere to show. - Does the icon name the kind of fact? If you cannot pick one, the fact may not need a tag.
Travels with#
FilterableCell, the dotted-underline filter button, for a plain value that filters. ATag onClickis the better cell when the fact is a label.StatusPill,ChipandFieldChip, the other three species.Tooltip, which the tag uses for a cut label.
Snippet#
import { Tag } from "@versable-git/ui";<div className="flex flex-wrap items-center gap-2"> <Tag Icon="Team">Walmart</Tag> <Tag Icon="Server">Production</Tag> <Tag Icon="FileSheet" onClick={() => setFileType("csv")}> CSV </Tag></div>