Badge
ImplementedNumeric count badge for notification and nav counts. Count-based API (number or max+), never children. Five semantic variants on ADR-027 tint/fg pairs — WCAG 2.2 AA (≥4.5:1) in light and dark themes.
src/components/atoms/Badge/Badge.tsxNumeric count badge for notification counts and nav item counts. Count-based API with a max cap and five semantic variants.
Badge
Count/Display atom (Tier 1)
A small numeric pill that communicates a count (notifications, nav items, cart lines). Renders a formatted number or `${max}+` — never free-form children.
This component supports light and dark mode.
Usage
The badge is count-based: it renders a number (or max+), not children. Always pass a descriptive ariaLabel when the bare number is ambiguous — the root is role="status" and announces the label. The variants use semantic colors tuned for WCAG 2.2 AA contrast on both light and dark surfaces.
import { Badge } from '@epasslive/design-system'
<Badge count={3} ariaLabel="3 new events" />
<Badge count={140} max={99} variant="error" ariaLabel="140 unread notifications" />
<Badge count={2} variant="info" ariaLabel="2 draft events" />
// Pair with a nav item for count display
<NavLink href="/dashboard">
Dashboard <Badge count={7} ariaLabel="7 pending orders" />
</NavLink>When to use
- Counts, not words — notification counts, nav-item counts, cart lines, filter results. For semantic states carried by a label (Confirmed, Pending, Refunded), use
StatusBadgeinstead. - Prefer badge slots — IconButton (
badge.count+showDot), Sidebar (badge.count+badge.ariaLabel) and Tabs (badgenumber) already position, cap and announce counts. Never hand-roll an absolutely-positioned count span. - Count-based API — pass
count(never children); counts abovemaxrender asmax+. - Localized apps — pass
ariaLabelfrom the translation catalog; the fallback accessible name is EnglishN item(s).
Dark mode
Four variants use ADR-027 semantic tint/fg pairs; neutral uses bg-3 + text-heading. All meet WCAG 2.2 AA in both light and dark themes.
Props
count*numberNumeric count to display. Must be a non-negative integer.
maxnumber99Cap the displayed value; counts above render as `${max}+`.
variant'error' | 'success' | 'warning' | 'neutral' | 'info''error'Visual variant — color encodes semantic intent.
ariaLabelstringDescriptive aria-label (e.g. ‘3 new events’). Falls back to `${count} item(s)`.
Props
Badge
countnumber—Numeric count to display. Non-integer inputs are floored; negative values clamp to 0.
maxnumber99Cap the displayed value; counts above render as `${max}+`.
variant'error' | 'success' | 'warning' | 'neutral' | 'info''error'Visual variant. error/success/warning/info use ADR-027 tint/fg pairs (WCAG AA in both themes); neutral uses bg-3/text-heading.
ariaLabelstring—Descriptive aria-label (e.g. '3 new events'). Falls back to `${count} item(s)`.
<Badge />Accessibility
Type
1 ruleARIA
1 ruleUsage
Import
import { Badge } from "@epasslive/design-system"Example 1
<Badge count={5} />Example 2
<Badge count={99} max={99} variant="error" />Example 3
<Badge count={3} variant="error" ariaLabel="3 new events" />Anti-patterns
— Do not compose atoms directly — use molecules instead
— Avoid inline styles on atoms
— Never pass children — the API is count-based (count or `${max}+`)