Skip to main content
Graphite UI

Tag

A short label for a status, a category or a count. It can be read-only, dismissible, selectable or operational, as the kit draws it. If the status needs a sentence, it is a Notification.

Contract 3.2.0Kit · 4 sets · 276 variantsOpen in Figma

Live preview

Rendered by the component itself from the same generated tokens as the rest of the site.

New

Installation

Install it with the shadcn CLI, along with everything it uses. New project? Set it up first, as Quick start shows.

npx shadcn@latest add https://www.graphite-ui.com/r/tag.json
import { Tag, SelectableTag, OperationalTag } from '@/components/ui/tag'

Anatomy

One slot: a short string or a number. The pill shape comes from the full radius, so the ends stay round at any label length.

Label
  1. LabelRequiredShort text, or a number capped at `max`.
  2. IconOptionalThe kit's leading Icon, a 16px glyph before the label. Decorative.

Variants

The kit’s eight Read-only colours plus warning, three sizes, an optional leading icon and a dismiss button, and the kit’s two interactive forms: selectable and operational. Neutral and Medium are the defaults. A number over max (99 by default) shows as 99+.

Variant: Neutral (default)
Draft
Variant: Primary
New
Variant: Secondary
Design
Variant: Info
Beta
Variant: Success
Paid
Variant: Danger
Failed
Variant: Warning
Expiring
Variant: High contrast
Pinned
Variant: Outline
Archived
Size: Small · Medium · Large
SmallMediumLarge
With a leading icon
Verified
Dismissible
DesignResearchOps
Disabled
Paused
Selectable
Operational
Count over max (128)
128

API reference

Generated from the contract, versioned with it, and checked by drift-check. This table cannot describe props the component does not have.

Tag props
PropTypeDefaultNotes
variant'neutral' | 'primary' | 'secondary' | 'info' | 'success' | 'danger' | 'warning' | 'high-contrast' | 'outline'—The kit's Tag - Read-only colours by role (Gray, Purple, Teal, Blue, Green, Red, High contrast, Outline), plus warning, which the kit does not draw. The operational form takes the first six.
size'sm' | 'md' | 'lg'—18, 24 and 32px, the kit's Small, Medium and Large. The label is 12/16 Regular at every size, inset 8 (12 at Large).
disabledboolean—
iconReactNode—
maxnumber99The cap for a numeric label. A number above it shows as the cap with a plus (99+), and the full number stays in the accessibility tree as visually hidden text.
onDismiss——The kit's Dismissible. A trailing close button, named "Remove <label>", that calls it.
dismissLabel——The close button's accessible name, for a dismissible tag whose label alone would not say what closing does (the multi-select's count tag, "Clear all selected items"). "Remove" and the label by default.
selected / onSelectedChange——The selectable form only, the kit's Tag - Selectable. A toggle button with aria-pressed.
onClick——The operational form only, the kit's Tag - Operational. A tag that opens or does something.

Design tokens

Every swatch is live. Change the source color in the header and this table repaints, because it reads the same roles the component does.

  • surface-variantFill on the neutral tag and on an unselected or disabled selectable tag.
  • on-surface-variantLabel on the neutral tag and an unselected selectable tag.
  • primary-containerFill on the primary tag and a selected selectable tag.
  • on-primary-containerTheir label.
  • secondary-containerFill on the secondary (Teal) tag.
  • on-secondary-containerIts label.
  • info-containerFill on the info (Blue) tag.
  • on-info-containerIts label.
  • success-containerFill on the success variant.
  • on-success-containerIts label.
  • danger-containerFill on the danger variant.
  • on-danger-containerIts label.
  • warning-containerFill on the warning variant.
  • on-warning-containerIts label.
  • on-backgroundFill on the high-contrast tag, the inverse pair.
  • backgroundLabel on the high-contrast tag.
  • surfaceFill on the outline tag, and a disabled close button.
  • on-surfaceLabel on the outline tag.
  • outlineThe 1px edge on the outline tag, an unselected selectable tag and a neutral operational tag.
  • primaryThe primary operational tag's edge and hover fill, the Tag focus ring (the kit binds primary here rather than the focus step), and the disabled fill, edge and label through its disabled steps.
  • on-primaryThe label on a hovered primary or danger operational tag.
  • secondaryThe secondary operational tag's edge.
  • infoThe info operational tag's edge.
  • successThe success operational tag's edge.
  • dangerThe danger operational tag's edge and hover fill.
  • spacingThe label inset, the icon inset and the close button's padding.
  • radiusPill shape, via `full`.
  • textThe label, Caption/1 12/16 Regular at every size.

Usage

The contract's prohibitions, written as the choices you will actually face.

Do

  • Keep the label to a word or two. A tag names a state, it does not explain it.
  • Say the status in the label text. "Failed" on danger reads without the colour; a red dot does not.
  • Pass a count as a number, not a string, so it caps at 99+ instead of widening the row.
  • Use neutral for categories that carry no status, so the status colours keep their meaning.

Don’t

  • Wrap a read-only tag in a link or click handler. A tag that does something is the operational form, which is a real button with a focus ring.
  • Pick a variant for its hue. With a red source colour, primary and danger look nearly the same.
  • Reach for warning casually. It is the one variant the kit does not vouch for.
  • Set a colour by hand for a status the variants do not cover. Use a generated role or use neutral.

Accessibility

What the component does for you, and what it leaves to you.

Roles
A read-only tag is a plain span, read inline as text, with no tab stop. The selectable form is a toggle button carrying aria-pressed; the operational form is a button; the dismiss control is a button named “Remove” and the label.
Focus
The interactive forms draw the kit’s Tag focus: a 2px primary ring 1px outside the pill, and a 1px primary ring inside the close button.
Colour
The variant colour is a second signal, never the only one. A source colour near a status hue collapses primary and danger, so the label text has to carry the meaning.
Counts
When a count is capped, the visible 99+ is aria-hidden and the full number is rendered as visually hidden text, so every screen reader reads the exact figure.
Contrast
Each variant pairs a container role with its own on-container role, and those pairs are measured at the theme’s target, AA or AAA.

Figma parity

The kit's Tag page ships 276 variants across 4 sets, one of them a private close button. The code exposes 9 props. This table is where those two facts are reconciled instead of quietly diverging.

Kit axes and how they map to code
Kit axisValuesCodeHow it maps
ColorBlue · Teal · Green · Purple · Red · Gray · High contrast · OutlinevariantAll eight: Gray is neutral, Purple primary, Teal secondary, Blue info, Green success, Red danger, plus high-contrast and outline. Warning has no kit colour.
SizeSmall · Medium · LargesizeOne to one: 18, 24 and 32px, the label 12/16 Regular at every size, inset 8 (12 at Large).
Icon · DismissibleBooleansicon · onDismissThe leading 16px icon and the trailing close button, as the kit stacks them.
StateEnabled · Disabled · SkeletondisabledDisabled is a prop. Skeleton has no counterpart: nothing loads into a tag.
Tag - SelectableSelected: False · TrueSelectableTagA toggle with aria-pressed. Hover is drawn identical to rest in the kit and is left that way.
Tag - OperationalEnabled · Hover · Focus · Disabled · SkeletonOperationalTagA button. The kit fills on hover only for Purple and Red; the other four are drawn identical to rest and left that way. The kit binds Purple’s hover label to the disabled tone, a slip; the code uses on-primary.