State label component

The status pill for a code-hosting entity (issue or pull request) whose value is drawn from a per-entity state machine, not a free tag. Distinct from a notification badge (count/dot) and a chip (user-editable filter): a state label is read-only, single-valued, and semantically colored by state. Modeled after GitHub Primer StateLabel. Used by Koder Flow issue lists, PR headers, dashboards, and any surface that shows VCS entity status.

Status: v0.1.0 — Draft. Promoted from the GitHub Primer parity scan (metadocsstack #092). Live URL once rendered: kds.koder.dev/<locale>/components/components-state-label.html. Source: https://primer.style/components/state-label

R1 — What it is (and is not)

A state label is a read-only pill bound to ONE value from a fixed, entity-specific state machine (R2). It is NOT:

  • a badge (specs/components/badges.kmd) — that signals a count/dot;
  • a chip (specs/components/chips.kmd) — that is user-editable / a

    filter input;

  • a free-text tag/label (issue labels are a separate, multi-valued,

    user-defined concept).

There is exactly one state label per entity instance.

R2 — State machines (closed sets)

The valid values and their semantics depend on the entity:

Issue

State Meaning Semantic color Icon
Open Active issue success (open-green) issue-opened
Closed — completed Resolved as done done (purple) issue-closed
Closed — not planned Closed without action neutral (grey) skip/circle-slash

Pull request

State Meaning Semantic color Icon
Draft Not yet ready for review neutral (grey) git-pull-request-draft
Open Ready / in review success (open-green) git-pull-request
Merged Merged into target done (purple) git-merge
Closed Closed unmerged danger (red) git-pull-request-closed

No other values exist. The state is derived from entity data, never set by hand in the view.

R3 — Anatomy

  • Pill container with a leading icon + a text label.
  • Sized in two scales: small (inline, in lists/tables) and default

    (entity header). Both keep the icon+label pair.

  • Fill uses the state's semantic color at the established surface

    contrast; the label text meets WCAG AA on that fill.

R4 — Color is never the only signal

Each state is distinguished by icon + text label, not color alone (WCAG 1.4.1). The icon shape per row in R2 is mandatory; a state label without its icon is non-conformant.

R5 — Tokens

All fills, text, and icon colors come from Verge semantic tokens (specs/themes/verge.kmd) — --kds-color-open, --kds-color-done, --kds-color-danger, --kds-color-neutral (or their canonical names). No raw hex. Light/dark are handled by the token layer, not by the component.

R6 — Accessibility

  • The label renders its state in words; the icon is decorative

    (aria-hidden) since the text carries meaning.

  • When used as the accessible name of an entity row, the state is part of

    that row's label ("Issue #214, Open").

  • Non-interactive: a state label is not a button/link. If a surface makes

    the surrounding row clickable, the click target is the row, not the pill.

R7 — i18n

The visible state label is translated per specs/i18n/contract.kmd ("Open"→"Aberto", "Merged"→"Mesclado", etc.). The underlying state KEY (used in code/filters) stays stable and language-invariant.

Não-escopo

  • User-defined issue labels (multi-valued, colored tags) — separate.
  • The state-transition rules themselves (owned by Koder Flow backend).
  • Review-decision states (approved / changes-requested) — those belong to

    the PR review surface (specs/components/ review spec, #138).