Badge

Labels a kind, a code or a trouble attribute next to what it describes.

Examples

Kinds after names

Workspace
5
support-agentAgent

Answers billing and refund tickets

triage promptv14

On 10% of conversations

Weekly evalEval

312 of 400 cases

model-sModel

Default for new agents

eval-runnerRead only

Used 2 h ago

In a list of recent changes

Recent changes4
3 waiting on you
prompt-v14DeployOver budget
POST/refunds503
support-widgetKeyRevoked
embed-smallBeta200

Styles

Status

  • Over budget

    warn

  • Revoked

    fail

Kind

  • Agent

    agent

  • Key

    key

  • Run

    run

  • Deploy

    deploy

  • Model

    model

Sizes

  • triage

    defaultdefault

  • Org

    sm

States

  • rest

  • hover

  • focus

  • 1,204

    capped

  • Retrying

    warn

  • Failed

    fail

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'
kind
Kind
status
'warn' | 'fail'
label
ReactNode
count
number
max
number default 99
render
ReactElement
CodeTag code
number | string
CodeTag 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

Install

For your coding agent

GitHub

Please star me pookie

141

A new design system every week

Leave your email before you copy the prompt.