AhaSlides Design
v0.52.0React · Vue · Lit

Patterns · composition guide

Status badges pattern

How to build a status/state pill on a domain object — dot + localised label, the aha-status-pill class convention, the role=status + aria-label contract, i18n labels, and colour driven by the modifier class — from existing components.

◆ generated from guidelines/status-badges.json + parts/status-badges.guide.md — do not edit by hand

A status pill communicates the lifecycle state of a domain object (a survey, presentation, or collector) in one glanceable, screen-reader-announced token. This pattern ships NO new component: it documents the markup, class convention, i18n and accessibility rules that keep every state indicator reading as one product, binding colour to semantic tokens via a modifier class rather than inline hex. The narrative 'why' lives in the aha-design-status-badges skill; this artifact carries only what the repo can enforce.

Based on

The rationale, worked examples, and the full assertion set live in the design skill — this pattern distils the enforceable subset and links each rule back to it.

build aha-design:aha-design-status-badges judge aha-design:aha-design-status-badges-judge

Choose the surface

SurfaceUse forExample
Dashboard list / cardthe lifecycle state of a survey, presentation, or collector rowdraft / published / closed / archived on a survey card
Admin / ops tablean enum-driven state column on a domain objectactive / inactive on an account row
Detail headerthe current state of the object being vieweda published badge beside a presentation title

Composed of

What a compliant status badges surface reuses from this design system — the pattern's link into the component graph.

ReusesKindForIn DS?
iconcomponentany glyph rendered beside the status (owned by aha-design-icons) — the dot itself is decorative CSS, not a glyphavailable
--aha-color-successtokenthe semantic colour a 'published'/'active' state maps to via its modifier class — never an inline hexavailable
--aha-color-errortokenthe semantic colour a 'closed'/failed state maps to via its modifier class — never an inline hexavailable
status-pillcomponentthe StatusBadge wrapper itself (aha-status-pill + dot + label) — the canonical element this pattern describesmissing
tagcomponentthe generic Tag for free-form labels this pattern explicitly is NOT (contrast target — a status badge is a fixed, semantic set, not a free-form Tag)available
badgecomponentthe generic count/notification Badge this pattern explicitly is NOT (contrast target — a status badge conveys state, not a count)available
⚠︎ 1 referenced component not yet in the DS — status-pill. composedOf marks 3 components this pattern references that the DS does not yet ship (status-pill, tag, badge). The status pill (StatusBadge / aha-status-pill family) is the primitive this pattern is built around and currently lives only in the product repo (features/dashboard/StatusBadge.tsx) — per the charter, a pattern that leans on a missing component is the signal to add it HERE. tag and badge are named as the primitives this pattern is NOT, so the roadmap keeps them distinct.

Rules

The shippable checklist — each rule traces to an assertion in aha-design:aha-design-status-badges.

RuleSkill assertion
Render a status pill only for a value from a known status enum (e.g. SurveyStatus: draft / published / closed / archived). Never use it for free-form labels, counts, or notification dots — those are AntD Badge/Tag territory.STATUS-01
A status pill is a single inline element containing exactly two parts: a dot span (aha-status-pill__dot) carrying the state colour, followed by the localised label text.STATUS-02
Markup is the base class aha-status-pill plus a per-state modifier aha-status-pill--{status}. Use the class convention, not a one-off prop or inline style.STATUS-02
Colour of the pill and its dot is driven by the --{status} modifier class, keeping every state's colour in one stylesheet and on semantic tokens. Never set the colour inline with a hardcoded hex.STATUS-03
The visible label is always sourced from i18n — t(survey_status.${status}) or the equivalent namespace for the object. Never hardcode the visible string.STATUS-04
Adding a new state means adding BOTH a translation key AND a --{status} modifier class — neither alone is complete.STATUS-03 STATUS-04
The element carries role="status" and an aria-label equal to the visible label, so the state is announced and not conveyed by colour alone.STATUS-05
State is never conveyed by the dot colour alone — the text label is always present and is the source of truth; the dot is decorative.STATUS-06
Carry a data-testid of status-badge-${status} on the pill so the rendered state is assertable.STATUS-02

Composition code

Doc-only — this pattern ships no wrapper from this repo. Doc-only pattern — ships no composition wrapper from this repo. The canonical StatusBadge component and the aha-status-pill class family live in the product repo at features/dashboard/StatusBadge.tsx; that is their source of truth. If the StatusBadge wrapper graduates into this DS, add a reuse block and it is gated like a leaf/composite.

Guide

Status badges — composition guide

The design system now OWNS this build ruleset — it is the single source of truth, and the aha-design-status-badges plugin skill is generated FROM this pattern. The skill keeps the rationale, worked BAD/GOOD examples, and the judge verdicts / evals (aha-design-status-badges-judge); this guide is the shippable checklist. When the two ever disagree, this pattern wins and the skill is regenerated.

A status pill communicates the lifecycle state of a domain object — a survey, presentation, or collector — in one glanceable, screen-reader-announced token. Its canonical form is the StatusBadge component and the aha-status-pill class family (features/dashboard/StatusBadge.tsx). This pattern adds no new control; it defines the markup, class, i18n and accessibility conventions that keep every state indicator reading as one product.

Companion skills. Use aha-design-icons for any glyph rendered beside a status,

the aha-branding:* colour skill for the semantic colour each state maps to, and aha-design-paywall for the crown badge (that is upsell, not status).

When to use a status pill

Use it to reflect a value from a known status enum (e.g. SurveyStatus: draft / published / closed / archived). Do not use it for:

  • free-form labels,
  • counts, or
  • notification dots.

Those are AntD Badge / Tag territory, not a status pill. *(STATUS-01)*

Anatomy

A status pill is a single inline element containing exactly two parts, in order:

PartClassRole
Dotaha-status-pill__dotcarries the state colour; decorative only
Label— (text node)the localised label text; the source of truth

``tsx <span className={aha-status-pill aha-status-pill--${status}} aria-label={label} role="status" data-testid={status-badge-${status}`}

<span className="aha-status-pill__dot" /> {label} </span> ```

(STATUS-02)

Class convention

  • Base class aha-status-pill plus a modifier per state: aha-status-pill--{status}.
  • The modifier — not an inline style or a one-off prop — controls the colour of the

pill and its dot. This keeps every state's colour in one stylesheet and on semantic tokens.

  • Never set the colour inline with a hardcoded hex. *(STATUS-02, STATUS-03)*

Labels come from i18n

  • The label is always t(\survey_status.${status}\) — or the equivalent namespace for

the object. Never hardcode the visible string.

  • Adding a new state means adding both a translation key and a --{status}

modifier class. Neither alone is complete. *(STATUS-03, STATUS-04)*

Accessibility

  • role="status" and an aria-label equal to the visible label, so the state is

announced and not conveyed by colour alone.

  • The dot is decorative — the text label is the source of truth, never the dot

colour by itself. State is never conveyed by dot colour alone; the text label is always present. *(STATUS-05, STATUS-06)*

Build checklist

#RuleRef
1Renders only for a known status enum — not free-form labels, counts, or notification dotsSTATUS-01
2Markup is aha-status-pill + aha-status-pill--{status}, with a dot span and a text labelSTATUS-02
3Colour is driven by the --{status} modifier class — no inline/hardcoded hexSTATUS-03
4The visible label is sourced from i18n (t('<namespace>.<status>')), never a hardcoded stringSTATUS-04
5The element carries role="status" and an aria-label matching the visible labelSTATUS-05
6State is not conveyed by dot colour alone — the text label is always presentSTATUS-06

*Full rationale, screenshots, and worked examples live in the aha-design-status-badges

skill. Self-check any built pill with aha-design-status-badges-judge and fix every FAIL before shipping.*