Photon Design System

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.

NeutralFreeProLiveDegradedFailed
<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.

NeutralFreeProLiveDegradedFailed
<Badge color="success" contrast="low">
  Live
</Badge>

Sizes

Four sizes — xs, sm, md (default), and lg — on a 4px height ladder (16 / 20 / 24 / 28). A badge is intentionally small: md is the working size and lg is the one step up, with the label at 14px, for a pill seated beside a page title (BasicPage.Title’s trailing slot). Use xs for chips inline with 14px labels (plan tiers).

ProProProPro
<Badge color="brand" size="xs">Pro</Badge>
<Badge color="brand" size="sm">Pro</Badge>
<Badge color="brand" size="md">Pro</Badge>
<Badge color="brand" size="lg">Pro</Badge>

Props

Badge renders a plain <span> and forwards every native span attribute.

  • color — gray · muted · brand · success · warning · error (default gray) — the semantic state the badge communicates
  • contrast — high · low (default high) — solid state fill, or the soft currentColor tint with a hairline ring
  • size — xs · sm · md · lg (default md) — fixed height (h-4 / h-5 / h-6 / h-7), 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 — Badge is 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 a Tag.
  • Color is decorative — color only 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 id and every span attribute, you can point a nearby control at it with aria-describedby when 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 a Tag.
  • Let color carry the meaning — success for healthy/live, warning for degraded, error for 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.