Badge
A small, non-interactive status label — a plan tier (Pro), a state (Live,
Failed), a count. Badge is a plain <span>, so it never takes focus or
handles clicks. For a dismissible or selectable chip, that’s a Tag; for a
standalone action, use a Button.
Import
import { Badge } from "@photon-ai/pho-ui/components/badge";
Colors
color is a tight, semantic set: gray (the default), muted, brand,
success, warning, and error. By default each fills the pill with its
state ink (or a soft surface for muted) so the badge reads at a glance.
<Badge color="gray">Neutral</Badge>
<Badge color="muted">Free</Badge>
<Badge color="brand">Pro</Badge>
<Badge color="success">Live</Badge>
<Badge color="warning">Degraded</Badge>
<Badge color="error">Failed</Badge>
Contrast
Two contrasts — high (default) and low. High is the solid state fill.
Low is the quiet material for dense chrome: text takes the state color, and
the soft fill plus hairline ring derive from it at low opacity.
<Badge color="success" contrast="low">
Live
</Badge>
Sizes
Three sizes — xs, sm, and md (default). A badge is intentionally small;
there is no lg. Use xs for chips inline with 14px labels (plan tiers).
<Badge color="brand" size="xs">Pro</Badge>
<Badge color="brand" size="sm">Pro</Badge>
<Badge color="brand" size="md">Pro</Badge>
Props
Badge renders a plain <span> and forwards every native span attribute.
- color —
gray·muted·brand·success·warning·error(defaultgray) — the semantic state the badge communicates - contrast —
high·low(defaulthigh) — solid state fill, or the soft currentColor tint with a hairline ring - size —
xs·sm·md(defaultmd) — fixed height (h-4/h-5/h-6), padding, gap, and label size - className —
string— merged onto the root<span> - …plus any
<span>attribute (id,title,data-*, event handlers)
The badgeVariants({ color, contrast, size, className }) helper is also
exported, for composing the badge’s look onto another element.
Accessibility
- Semantics —
Badgeis a plain<span>with no ARIA role, so assistive tech reads it inline as text. Keep the label meaningful on its own (Failed, not a bare color) — the text is the only thing announced. - Not interactive — it never takes focus and has no keyboard behavior by
design. If tapping it should do something, that’s a
Button; if it can be dismissed or toggled, that’s aTag. - Color is decorative —
coloronly tints the badge; it conveys nothing to a screen reader and nothing to anyone who can’t tell the hues apart, so never let it be the only signal. - Relating it to a control — because it forwards
idand every span attribute, you can point a nearby control at it witharia-describedbywhen the badge annotates something whose reading order doesn’t already make the link clear.
Best practices
- Reach for a badge to label state or a category — a plan tier, a health state,
a count. It’s not a button: if tapping it should do something, use a
Button; if it can be dismissed or toggled, that’s aTag. - Let
colorcarry the meaning —successfor healthy/live,warningfor degraded,errorfor failed — and keep the label to a word or two. - Don’t rely on color alone; the text should still read on its own for anyone
who can’t distinguish the hues (
Failed, not a bare red dot). - Keep to one badge per item where you can. A row crowded with badges dilutes the signal each one is meant to give.