Skip to content
View as Markdown

Data display

Badge

A compact pill for statuses, counts, and labels.

Import

TSX
import { Badge } from "@loamui/core";

Usage

Every example has a CSS tab. That’s the real, complete stylesheet for the component: plain, static CSS, with nothing running in the browser.

Contexts

Badges are neutral by default. There are no variant or colour props: declare --loam-context on a one-element wrapper region (see the Contextualism guide) and the status colours follow, or let it inherit from a larger region. Badge keeps a size prop because it sizes an intrinsic glyph, the one exception the library makes for display components (Badge, Loader, Progress).

NeutralPrimarySuccessWarningDangerInfo

Sizes

size is one of three tokens, emitted as data-size: the type step, with the pill's geometry in em on it. It is the one size prop the library keeps for display components, because a pill is an intrinsic glyph that no container can size.

SmallMediumLarge

Status icons

An icon before the label takes the region's colour along with the pill, so a status reads before the word does. It is aria-hidden decoration: the word carries the state, and Draft has no context, so it stays neutral.

LivePendingOfflineDraft

Icons (composed as children)

No leftSection / rightSection props: an svg child is detected via :has(svg) and gets a gap and 1em sizing, exactly like Button.

Verified

Guidance

When to use it

  • To label a record with its status or category at a glance: one or two words sitting next to the thing they describe, readable without reading the row.
  • For small counts and metadata (unread messages, item totals) where a full sentence would drown the signal.
  • With an icon for presence and liveness (“Live”, “Offline”): the icon takes the region's colour along with the pill, so the state reads even before the word.

When not to

  • As a click target for an action. Badge renders a plain <span> with no role, focus or keyboard handling. A tag that navigates is render={<a href />}; a status that triggers something is a Button beside it.
  • For sentences or long labels. The pill is white-space: nowrap, so long text will not wrap; it is built for one or two words.

Accessibility

  • Renders a plain <span> with no role and no focus behaviour: screen readers announce it as ordinary inline text, exactly what a label should be.
  • A status icon is aria-hidden decoration, so the visible word must carry the state on its own (“Live”, not a bare green glyph). It is drawn in currentColor, which system colours replace, so it survives forced-colours mode where background paint is stripped.
  • The context colours the pill but is never announced. Assistive tech hears only the text, so never let colour be the only difference between two badges.
  • The label is not the raw status colour: it is mixed toward black (light scheme) or white (dark) so it keeps contrast on the pill's own tint in both schemes.

How it works

One or two words

A badge is metadata absorbed at a glance while scanning past it. The moment the label needs a verb it has become content, and content belongs in text the eye is meant to stop on. The nowrap styling enforces this: prose in a badge will not fit.

Never interactive

The rendered element is a span with no interactive semantics, and that is deliberate: a status is a fact, not an affordance. An onClick on it creates a control that keyboards and screen readers cannot find. The one interactive badge is a link, because a tag can lead to everything it tags: render={<a href />} keeps the pill on a real <a>. An action belongs on a Button beside it.

Parts

Badge.Root

The pill. Holds a Badge.Text and, on either side of it, any icon children — the markup says which side.

PropTypeDefaultDescription
size"sm" | "md" | "lg""md"Control size: the type step, with the pill's geometry in em on it.
renderelement | (props) => node—Substitute the element (render={<a href=… />} for a tag that is a link); the Badge's class and attributes merge onto it.
childrenReactNode—A Badge.Text, and any composed icons beside it.
...othersSpanHTMLAttributes—All native <span> props are forwarded.

Badge.Text

The label. A real element rather than a bare text node, so the pill can let it shrink and truncate; bare text in the flex row is an anonymous item and can do neither. Native <span> props are forwarded.