Badge
Labels a kind, a code or a trouble attribute next to what it describes.
Examples
Workspace
5Recent changes4
3 waiting on you
| prompt-v14Deploy | Over budget |
| POST/refunds | 503 |
| support-widgetKey | Revoked |
| embed-smallBeta | 200 |
Styles
- Read only
secondarydefault
- Admin
outline
- +3
ghost
link
Status
- Over budget
warn
- Revoked
fail
Kind
- Agent
agent
- Key
key
- Run
run
- Deploy
deploy
- Model
model
Sizes
- triage
defaultdefault
- Org
sm
States
Usage
When to use it
- Use
- A row or header needs the kind, category or count of a thing, read at a glance.
- Use
- A state is static while the view is open: over budget, revoked, read only.
- Use
- A row shows an HTTP method or status code: CodeTag.
- Use
- A title or row says which kind of thing it is: follow the name with a kind label, never an icon.
- Not for
- The person can press it to filter, remove or open a menu. Use Chip.
- Not for
- The state changes while the person watches: queued, running, ok. Use Status.
- Not for
- A big number is the point of the view. Use Stat.
- Not for
- A message about trouble needs a sentence and an action. Use Alert.
Rules
11 rules
- Must
- Pass kind for agent, key, run, deploy or model; never a colored class. Because kind sets data-kind, the word and the tint together, and a hand-set class misses the label step that passes contrast.
- Must
- Follow the name with the quiet kind word; no hue square and no icon. Because the name is what the person scans for, and a square or icon in front pulls the eye to the kind instead.
- Never
- Fill a badge with ink; a count waiting on the person reading is an InkSlot, the paper waiting label. Because ink fill is the primary action, and an ink badge for a plan or a category makes a label look like something to press.
- Must
- Write HTTP methods and status codes with CodeTag; never colour a method. Because CodeTag puts the status on the line and keeps the text ink, and a red DELETE reads as trouble when it is a normal call.
- Should
- Show 3 badges of one sort and a ghost +n badge for the rest.
- Must
- Pass the number to count; it caps at max and keeps the exact figure for screen readers. Because a hand-made "99+" is all a screen reader hears, and the real number is lost.
- Should
- Write 1 to 3 words in sentence case, or one identifier, with no end punctuation. Because the badge is whitespace-nowrap, so a sentence runs out of its row.
- Never
- Put onClick on a Badge; render it as a link with render={<a href/>} or use Chip. Because Badge renders a span, so it takes no focus, no Enter and no button role.
- Never
- Color badge text for good or bad; trouble is outlined in its line step with ink text (status warn or fail). Because green is not a Quartz status, and hue alone vanishes for color-blind readers and in forced colors.
- Never
- Round a badge into a pill; keep the 4px inner corner. Because round belongs to person avatars and radios in Quartz, so a pill badge reads as one of them.
- Should
- Wrap a label that may pass 24 characters in a truncate span and set max-w-full. Because the badge never wraps, so a long model name pushes its row wider than the column.
Accessibility
5 checks
- A badge takes no focus; only a badge rendered as a link does, with a 2px ink outline.
- A kind badge names its kind in a word; the hue never carries it alone.
- A capped count keeps the exact figure in the title and the accessible name.
- Keep the label at 4.5:1 on its tint in both themes; outlined text is ink on paper and its line is 3:1.
- A badge link is 20px tall; give it 4px of gap or set it inside running text.
Edge cases
11 edge cases
- Long label
- Never wraps; truncate it with max-w-full and a truncate span.
- One character
- Keeps a 20px minimum width, so "1" is a square.
- No children
- Renders an empty 20px square with no name; render nothing instead. count={0} shows "0".
- 25 badges in a 160px row
- Wrap with flex-wrap; in a nowrap row they push it wider.
- Right to left
- Padding is symmetric; the label reads from the start.
- Zoom 200%
- Height grows with the text; min-h-5 holds the box.
- Text spacing
- The badge widens; nothing clips.
- On a warn or fail row
- The outline keeps its line on the wash; the text stays ink.
- Count waiting on data
- Leave the badge out until the number lands; never show "0".
- NaN or negative count
- Renders "NaN" or "-3"; pass finite non-negative integers.
- Forced colors
- Fills drop; label sizes take a 1px CanvasText outline.
API
11 props
variant'secondary' | 'outline' | 'ghost' | 'link'default'secondary'size'default' | 'sm'default'default'kindKindstatus'warn' | 'fail'labelReactNodecountnumbermaxnumberdefault99renderReactElementCodeTag codenumber | stringCodeTag status'neutral' | 'warn' | 'fail'CodeTag fill'soft' | 'solid' | 'outline'default'soft'
Tokens
12 tokens
--accent-tint- var(--surface-selected)
--accent-label- var(--text-1)
--accent-line- var(--ink)
--line-control- oklch(var(--ink-c) / 0.16)
--surface-page- var(--paper)
--text-1- var(--ink)
--text-2- oklch(var(--ink-c) / 0.80)
--surface-hover- oklch(var(--ink-c) / 0.05)
--dur-fast- 120ms
--type-label-sm- 400 12px/16px var(--font-sans)
--type-tag- var(--type-code-sm)
--radius-inner- 4px