Skip to content

Components · Data display

StatusBadge

Typed status registry: label, tone and a distinct icon or dot, so colour is never the only signal.

@rookcom/monarch-reactComponent

Service health

OperationalDegradedPartial outageDownMaintenanceUnknown

Usage examples

Variants

Your own statuses

Custom colours, contrast-guarded

Purpose

Shows the state of a thing (a service, a request, a sync) from a typed registry that maps each status value to a human label, a semantic tone and an icon. Products add their own statuses, including workspace-defined colours, which pass through a contrast guard.

Use when

  • A value comes from an enum (partial, pending_delete) and needs a consistent label, tone and icon everywhere it appears.
  • Service health: operational, degraded, partial outage, down, maintenance, unknown.
  • Users or workspaces define their own statuses with colours.

Avoid when

  • A free-form tag or count with no status meaning: use Badge.
  • The status must be changed in place: put a Select or DropdownMenu next to it (an editable picker is not part of StatusBadge).

Design principles

  • Colour is never the only signal: every badge has text, and the built-in statuses have distinct icon shapes (check, triangle, half-filled circle, cross, wrench, dashed question).
  • One registry, one meaning: define a status once with defineStatuses and every screen shows it the same way.
  • Never a raw enum. Unknown values render in the neutral look with a readable label ("Pending delete").
  • Custom colours mark, text reads: a custom colour tints only the dot, icon and border, and is adjusted per theme until it reaches the non-text contrast target.
  • Calm by default: subtle and dot for tables and lists; solid only for the one status that matters most on a screen.

API reference

import { StatusBadge, StatusRegistryProvider, builtInStatuses, checkStatusColor, defineStatuses, formatStatusLabel, resolveStatus } from '@rookcom/monarch-react';
ExportKindRenderingRoot class
StatusBadgecomponentclient.mn-status-light
StatusRegistryProvidercomponentclient.mn-status-light
builtInStatusesutilityclient–
checkStatusColorutilityclient–
defineStatusesutilityclient–
formatStatusLabelutilityclient–
resolveStatusutilityclient–

builtInStatuses is the shipped registry. defineStatuses(defs, { extend? }) returns a typed registry and rejects colours that are not #rrggbb.

StatusRegistryProvider makes a registry available below it; nested providers add up. Lookup order: the statuses prop, the nearest provider, then the built-in set.

resolveStatus(status, ...registries) and formatStatusLabel(status) are the same lookup and label formatting, for legends and tooltips.

checkStatusColor(hex) is the contrast guard; it returns the per-scheme colours, the readable text colour for solid fills, and the original ratios.

Generated from the TypeScript declarations of packages/react/src/components/data-display/status-badge.

Properties

status autocompletes the built-in keys and accepts any string from your own registry.

StatusDefinition.description is data for the product’s tooltip or legend; StatusBadge does not render it, because a tooltip on a non-focusable badge is not reachable by keyboard.

StatusBadge

A status shown as text plus a tone and a distinct icon or dot, so colour is never the only signal. Statuses come from a typed registry that products extend with `defineStatuses` and `StatusRegistryProvider`.

PropTypeDescription
status required"danger" | "success" | "warning" | (string & {}) | "neutral" | "info" | "down" | "maintenance" | "operational" | "degraded" | "partial" | "unknown" | nullThe status key: a built-in one or one from `statuses` / a StatusRegistryProvider.
childrenReactNode
classNamestring
colorstringOverrides the registry colour (`#rrggbb`), passed through the contrast guard.
iconReactNodeReplaces the registry icon. `false` hides it (the text still carries the meaning).
idstring
labelReactNodeOverrides the registry label, for example with a translated string.
size"sm" | "md"
statusesReadonly<Record<string, StatusDefinition>>Statuses for this badge only, checked before the provider and the built-in set.
variant"subtle" | "solid" | "outline" | "dot"`subtle` (default) tinted pill; `outline` for dense tables; `solid` for a single prominent status; `dot` for a quiet coloured dot plus text.

StatusRegistryProvider

Makes a product's statuses available to every StatusBadge below it. Nested providers add up.

PropTypeDescription
children requiredReactNode
statuses requiredReadonly<Record<string, StatusDefinition>>Statuses added to (and overriding) the built-in set for everything inside.

Variants

PropValuesDescription
variant'subtle''outline''solid''dot'Tinted pill (default), bordered pill, filled pill, or a coloured dot with plain text. Exposed as data-variant.
size'sm''md'Height and text size. Default md.
tone (registry)'neutral''accent''info''success''warning''danger'Set per status in the registry, exposed as data-tone.

States

StateExposed asBehaviour
Known statusdata-status, data-toneLabel, tone and icon from the registry.
Unknown statusdata-known="false"Neutral tone, dashed question icon, readable label from the raw value.
Custom colourdata-custom-colorGuarded --mn-status-light and --mn-status-dark colours mark the dot, icon and border. A custom status without an icon gets a dot, so the colour always shows.

Not interactive: no hover, focus or disabled states.

Interaction behaviour

Not interactive. Wrap it in a button or link when it should do something.

Keyboard support

Not focusable; the text is read in the normal reading order.

Accessibility

Role
none (inline text)
Accessible name
Its visible text.
  • Icons and dots are aria-hidden; the label alone carries the meaning.
  • Distinct icon shapes keep built-in statuses apart for people who cannot tell the colours apart (WCAG 1.4.1).
  • Custom colours are guarded to 3:1 against the surface in light and dark, and to the more-contrast target in those themes (WCAG 1.4.11). Solid fills pick a text colour of at least 4.5:1.
  • In forced-colours mode the border and dot use system colours.

Responsive behaviour

  • Never wraps; long labels truncate with an ellipsis inside a narrow cell (max-width: 100%).
  • Same size at every viewport width.

Theme support

  • Tones use the Monarch intent tokens (--mn-color-<tone>-subtle, -strong, -border, -solid), so all themes work.
  • Custom colours carry a light and a dark value; the dark one applies under .dark or [data-mn-theme="dark"].
  • The accent tone follows the product accent; the status tones do not.

Do and don't

Do

  • Define each product vocabulary once with defineStatuses and share it through a provider.
  • Translate with the registry label or the label prop, never by showing the enum.
  • Use dot in dense tables and subtle elsewhere.

Don't

  • Do not hide the label to save space; colour alone fails people who cannot see it.
  • Do not hand-pick raw palette colours for statuses; use a tone, or a guarded custom colour.
  • Do not put explanations only in a title attribute; show them in text or a focusable tooltip trigger.
  • Badge: Free-form labels and counts without a status meaning.
  • Tooltip: Explain a status from a focusable trigger next to it.
  • Alert: A status that needs a message and an action.

Dependencies

KindDepends on
npm packages@rookcom/monarch-tokensreact
Monarch componentsNone

Uses the tokens package’s colour maths (contrast, ensureContrast) and theme surfaces for the contrast guard; it is already a peer dependency.

Testing coverage

  • Renders label, tone and a decorative icon for a built-in status.
  • Every built-in status has a label and an icon.
  • Unknown and null values render a readable label in the neutral look.
  • Dot variant shows a dot and text without the icon.
  • Icon slot replaces or hides the icon; label overrides the registry label.
  • Products extend the registry through a provider and the statuses prop; defineStatuses extends the built-in set and rejects malformed colours.
  • Lookup order and label formatting.
  • Contrast guard: keeps passing colours, adjusts failing ones to the target in all four themes, solid text at 4.5:1 or more, rejects non-hex input.
CheckCovered
Axe in jsdomYes
Server renderingYes
Browser suitesVisual baselines: /__gallery; Cross-browser axe: /components/status-badge

Tests: packages/react/src/components/data-display/status-badge