Skip to content

Badge · Chip

Badge — a small square label that names a state, a category or a count.

Beta · Feedback and status · packages/css/src/components/badge.css · React on Base UI: @pepperui/badge

.pui-badge (square, radius 4; --small --large) · .pui-chip (pill, chip/radius; --small) · tones --blue --red --yellow --green --dark · __icon. Labels are pills, actions are squares.

Badge · Chip — every size and every stateOpen in the workshop

Sizes across, states down.

  • Tone: neutral, blue, red, yellow, green, dark — a tone is fixed; it does not follow the slide accent
  • Size: small (the site tag), medium (the slide’s --xs and the deck tool’s app badge), large (the slide badge)
  • Label is a text property; Has icon + Icon for a 16px leading glyph; the gap is space/4. THE GLYPH TAKES THE BADGE OWN INK — tint/{tone}/fg, text/on-inverse on dark — never text/default. In CSS that is currentColor and free; in Figma a swapped Icon arrives bound to text/default, so recolour the instance stroke
  • No states: a badge is not interactive. If it needs hover or focus it is a Toggle, or a Chip with an action
  • Square, radius 4 — the tag shape. The pill is Chip
  • NO BORDER, on any tone, in any size. The one ring in the library is not the Badge’s: a KPI tile rings its STATUS DELTA — green up, red down — with a 2px kpi/delta/ring stroke, because that badge sits on the tile’s tint and is the one thing saying good or bad. A badge wearing a card’s own tint is a label and stays flush, and so does a badge anywhere else — a table row, a card, a topbar, a tag on a page

Use when a status word on a KPI tile or a table row, a category tag on a card, a small count.

Do not use when it can be clicked (Toggle, Button); it is a state the user changes (Switch, Select); the label runs past two words — that is a sentence.

Relates to Chip (the pill), KPI tile (its status badge), Table (pills in headers), Card.

Anti-patterns a border on a badge (the delta ring is the tile, not the badge) · a glyph in a different ink from its label · red for anything that is not a problem · yellow text at the main step · a badge styled as a button · more than two tones in one row of tags · ALL CAPS.

Keywords: badge, tag, label, status, category, count

Chip is the removable / selectable form; one item, two exports

Figma — page Badge & Chip: Badge (18 variants) · Chip (12 variants)

shadcn: badge

The class, the parts, and nothing that is not in the package. The same block opens badge.css.

<span class="pui-badge pui-badge--green">Done</span>
<span class="pui-chip pui-chip--blue pui-chip--small"><span class="pui-icon pui-chip__icon">…</span>Beta</span>
What it is Note
Tone (none) neutral · --blue · --red · --yellow · --green · --dark fixed; never follows the accent
Badge --small 12 Regular 2 / 4 · (none) medium 14 Regular 4 / 8 · --large 18 Medium 8 / 12 —
Chip --small 12 Regular 2 / 8 · (none) medium 14 Medium 4 / 12 —
Parts __icon — a 16 px leading glyph at a space/4 gap. It takes the label’s ink, because it inherits currentColor and nothing here overrides it; in Figma the same rule costs a recolour on every swapped Icon, which is why it is written in both contracts. —

Rule — the pills-vs-squares test reads these two radii.

Rule — NO BORDER, on any tone, in any size — a label is flush. The library’s one ring is not the Badge’s: a KPI tile rings its DELTA with kpi/delta/ring because the delta sits on the tile’s tint (kpi-tile.css). css_rules_test.py fails on a border or a ring declared here.

Every number here is measured on the rendered component: contrast (npm run contrast:render), the focus ring (npm run focus) and the keyboard (npm run keyboard). The floors are principle 12’s.

ink on ground reads floor the matrix calls it
#ec6663 on #f9d3d2 2.29 4.5 Red badge / chip (exempt) axe
#6a66e4 on #d4d3f7 3.12 4.5 Blue badge / chip (exempt) axe
#1a6b36 on #d4f2de 5.48 4.5 Success badge (promised) ok
#634e0f on #fad567 5.62 4.5 Yellow badge / chip (promised) ok
#544d4d on #dad9d9 5.85 4.5 text.muted on ground.card.sunken (promised) ok
#544d4d on #ffffff 8.24 4.5 text.muted on surface.page (promised) ok
#ffffff on #231b1b 16.88 4.5 text.on-accent on surface.inverse (not-offered) ok

7 distinct pair(s) rendered, 2 that axe calls a violation — each one carries its reason in storybook/test/axe-allowlist.json.

Nothing in this component takes focus.

Nothing in this component claims an ARIA role with a keyboard contract; its controls are ordinary ones and the browser already gives them their keys.

Tab order across the whole library is document order over 344 stops, and Shift+Tab is its exact reverse — no keyboard trap anywhere (WCAG 2.1.2).

Pepper UI v1.5.0

The Mobupps design system. 386 tokens, 88 components, 65 pages in the workshop — every page of this site generated from the repository, so nothing here is typed twice.