Components / Badge
Badge stable
A small pill label for status and metadata — camp availability ('Open · 12 spots', 'Sold Out', 'Waitlist'), the 'Beestera' eyebrow, and filter chips. Uppercase, caps-tracked, semibold.
Source: specs/badge/spec.json · specs/badge/notes.md
Live preview
Rendered from the tier-2 component tokens + foundation tokens per this spec — a spec-faithful rendering, not the production component (those live in each product repo). Variants and states come from the spec below.
RecommendedHalf dayOpen · 12 spotsWaitlistAlmost fullComing soon
Anatomy
root- The pill: rounded-pill shape, tinted background, compact padding.
label- The text — uppercase, caps tracking, small size, semibold.
dot- Optional leading status dot (e.g. green for Open) coloured by the tone accent.
Token bindings
Each binding's value is resolved live from the built
@beestera/tokens output — tier-2 component tokens
(--badge-*) collapse through the foundation tier.
| Part | Property | Token | Resolved | Applies to |
|---|---|---|---|---|
root | border-radius | --badge-radius | 9999px --badge-radius → --radius-pill | — |
root | background | --badge-bg | #fafafa --badge-bg → --color-surface-alt | tone:neutral |
label | color | --badge-fg | #3d3d3d --badge-fg → --color-muted | tone:neutral |
label | font-size | --badge-text | 0.75rem --badge-text → --text-small | — |
label | letter-spacing | --badge-tracking | 0.06em --badge-tracking → --tracking-caps | — |
root | background | --color-brand | #ffd700 | tone:brand |
label | color | --color-ink | #181818 | tone:brand |
root | border-color | --color-success | #178640 | tone:success |
root | border-color | --color-danger | #dc2626 | tone:danger |
root | border-color | --color-warning | #a26807 | tone:warning |
root | border-color | --color-info | #1a6df4 | tone:info |
label | color | --color-ink | #181818 | tone:success |
Variants
-
tonebrandneutralsuccessdangerwarninginfo - Semantic tone. brand = yellow fill with ink label; neutral = surface-alt fill; status tones (success/danger/warning/info) are a tinted surface-alt with an ink label and a coloured accent border, keeping label contrast AA.
State matrix
default- Static label — the badge is non-interactive by default.
Accessibility
- Role
- none (decorative label). If it conveys status not otherwise in text, expose it via an accessible name.
- Contrast
- Label vs background >= 4.5:1 (WCAG AA text). Status tones keep an ink label on a tinted background; the saturated semantic colour is reserved for the border/dot, never the label text.
- Focus order
- Not focusable when static. Filter-chip usage (interactive) is a separate concern and MUST be a real control.
- Target size
- n/a for static badges.
- Never use yellow (brand) as label text on a light background — the brand tone uses ink text on the yellow fill.
- Status colour lives on the border/dot accent, not the text, so contrast holds.
Usage
Do
- Use tone to signal meaning (success = Open, danger = Waitlist/urgent, neutral = metadata).
- Keep labels to 1-3 words.
- Pair a status dot with tone for at-a-glance scanning where space allows.
Don't
- Don't put long sentences in a badge.
- Don't colour the label with the saturated semantic token (fails contrast).
- Don't reuse the static badge as a clickable filter chip without making it a real button.
Implementations
-
swarm-os -
packages/ui/src/Badge.ts—buildBadgeViewShips tone: brand|neutral|success|danger|warning|info. Status tones use bg-surface-alt + text-ink + a coloured border, matching this spec.
Figma source: Component / Badge / Availability