Skip to content
SproutAceve · v3.30.0
Overview What is your role? Connect to Sprout MCP reference Adopting Sprout
Brand & logos Color Typography Spacing & layout Elevation Iconography Accessibility
Overview Alert Avatar Badge Breadcrumb Buttons Cards Checkbox Data grid Dialog Floating tabs Inputs Menu Navigation Numeric input Ribbon toolbar Switch Tabs Tag Tooltip
Interaction & motion Voice & content Product patterns
AI patterns AI transparency & disclosure AI disclosure label
Design principles Personas Trust and ethics Meet the makers
Build the systemplay Tower of tokensplay Site runnerplay
How it works Changelogv3.30 Roadmap Contribute
Components

Tag.

A tag is a compact, non-interactive label that classifies the thing next to it — a status, a type, an owner, a count. It earns its place when the same information would cost a whole sentence in the row. Five colour variants carry meaning, so the label has to say the same thing the colour does: a reader who cannot separate the greens from the reds should lose nothing. Tags add clarity, not decoration; a row wearing four of them is telling you the table needs a column instead.

Variants

CategoryPrimary
InvoiceNeutral
ApprovedSuccess
ExpiringWarning
OverdueDanger
VariantWhen to useFill / border / label
primaryThe default. A category or attribute that carries no status meaning of its own.#F4FFE0 / #447952 / #152F1A
neutralPlain metadata — a type, an owner, a document number. Reach for this before Primary when nothing is being signalled.#F2F2F2 / #000000 / #0D0D0D
successCompleted, approved, active, paid.#C2F8DD / #119754 / #052D19
warningNeeds attention but nothing is broken yet: expiring, pending, on hold.#FDEDAA / #BF9C0C / #2F2603
dangerFailed, rejected, overdue, blocked.#FFE7E2 / #E1563B / #441A12

All five label colours clear 4.5:1 against their own fill. What the palette cannot do is carry meaning on its own — under WCAG 1.4.1 the label text has to say what the colour says, so "Overdue" in Danger, never a red tag reading "Invoice 4417". Keep one variant meaning one thing across a product; a Warning tag that means "draft" in one screen and "expiring" in the next is worse than no colour at all.

Size

CategorySmall28 px tall · 8 px side padding · 12 px label
CategoryMedium38 px tall · 12 px side padding · 14 px label. The default.
CategoryLarge48 px tall · 16 px side padding · 16 px label

Match the tag to the type around it, not to the space available: Small inside dense table rows, Medium in cards and detail panels, Large only where the surrounding type is 16 px too. A Large tag next to 14 px body text reads as a button and invites a click that does nothing.

Shape & options

CategorySquare — Rounded = no4 px radius. The default.
CategoryPill — Rounded = yesFully rounded. Pick one shape per product and keep it.
CategoryWith icon — Show icon = onA 14 px leading icon. The default glyph in the set is pen-to-square, which suits almost no tag.
FrontendRemovable = YesAdds a trailing 14 px xmark and drops the leading icon — the two cannot coexist.

Removable turns a label into a control, and that changes what the component owes the user: a real button with its own accessible name, a keyboard route to it, a visible focus ring and a 24 × 24 px target. The Figma set provides none of those today — no hover, no focus, no disabled state. An interactive tag needs states; the demo above adds them rather than reproducing the gap.

Anatomy

Frontend
Show icon + label
Frontend
Label + remove
Height38 px at Medium — 28 px Small, 48 px Large. Fixed, not derived from padding.
Side padding12 px at Medium — 8 px Small, 16 px Large.
Icon to label gap12 px on the square Medium, but 8 px as soon as Rounded = yes or Removable = Yes. Unintended — flagged below.
LabelManrope Medium 14 in the variant label colour — 12 px Small, 16 px Large.
Leading icon14 px, optional through Show icon. Instance-swap; the set default is outlined/pen-to-square.
Remove affordance14 × 14 px glyph; the demo above wraps it in a 24 × 24 px button, see Accessibility.
Border1 px solid in the variant border colour, on every variant.
Radius4 px — 9999 px when Rounded = yes.
Vertical paddingDeclared as 12 px top and bottom at Medium, which cannot be true inside a fixed 38 px height with a 19 px label. The declared value is dead — flagged below.

Two things in the Figma component don't hold up under this anatomy: the icon-to-label gap silently drops from 12 px to 8 px the moment Rounded or Removable turns on, with no stated reason, and the declared 12 px vertical padding at Medium is mathematically impossible inside a fixed 38 px height holding a 19 px line box — the value sits in the panel but nothing reads it. Reproduced as specified above; flagged here rather than quietly fixed.

Do & don't

ApprovedPendingOverdue
Do — keep one colour meaning one thing, everywhere in the product.
OverdueApprovedPaid
Don't — colour a tag against its own label — the reader believes the colour first.
InvoiceFrontend
Do — keep labels to a word or two, so the tag stays scannable at row height.
Awaiting approval from the site manager before dispatch
Don't — flood the tag with a sentence; at that length it is a field, not a tag.
OverduePaid
Do — say it in the label, so the meaning survives without the colour.
Add filterExport
Don't — make a tag do a button's job — it looks pressable and has no hover, focus or disabled state.

Accessibility

Static tagPlain text. No role, no tab stop. Never add role="button" or tabindex to a tag that does nothing when clicked.
Removable tagThe xmark is a real <button> nested inside the tag, in the tab order, with its own accessible name.
Accessible name"Remove Frontend" — not "Remove", and never a bare "x". Once several tags sit in a row, the label is the only thing that separates one remove button from the next.
KeyboardTab reaches the remove button; Enter or Space activates it. With focus on the tag itself, Backspace and Delete remove it and Escape blurs — the convention MUI Chip follows.
After removalMove focus to the next tag, or to the container when the last one goes. Announce it in a polite live region: "Frontend removed."
Focus indicatorNot in the Figma component. Proposed and implemented in the demo: a 2 px accent outline at 2 px offset, drawn outside the border so the tint does not swallow it.
Target sizeThe remove glyph is 14 × 14 px. WCAG 2.5.8 asks for 24 × 24 px — the demo above grows the hit area, not the glyph.
Not colour aloneThe variant colour is decoration. The label carries the meaning, which is what satisfies 1.4.1.
ContrastAll five label-on-fill pairs measure 4.5:1 or better. Borders are decorative and exempt from 1.4.11.
Groups of tagsWrap a set in a list so a screen reader announces how many there are. A bare row of spans gives no count.
TruncationIf a label has to truncate, the full text stays the accessible name. A title attribute alone is not a substitute.

Props (React) — draft

// DRAFT. Derived from the Figma properties plus the MUI Chip accessibility notes.
// Anything marked (proposed) does not exist in the Figma component yet.

type TagProps = {
  variant?: "primary" | "success" | "neutral" | "warning" | "danger";  // Figma: Variant
  size?: "small" | "medium" | "large";   // Figma: Size
  rounded?: boolean;                     // Figma: Rounded
  removable?: boolean;                   // Figma: Removable
  showIcon?: boolean;                    // Figma: Show icon
  label: string;                         // Figma: Label
  icon?: ReactNode;                      // (proposed) instance-swap slot in Figma
  onRemove?: () => void;                 // (proposed)
  removeLabel?: string;                  // (proposed) e.g. "Remove Frontend"
};

// (proposed) States the set does not carry at all: hover, focus-visible, disabled.
// They only matter once removable is true — and the answer is yes, an interactive
// tag needs states; a smaller prop surface is not a reason to skip them.

// Not a prop: showIcon and removable cannot both be on. The Figma set drops
// the leading icon when Removable = Yes, so the API should make that explicit.
← PreviousTabsNext →Tooltip
Sprout · Aceve Design System · v3.30.0
Figma library GitLabReleases