Skip to content

State label component

components specs/components/state-label.kmd

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.

When this spec applies

Primary triggers

All triggers

Specification body

Component — State label

Status: v0.1.0 — Draft. Promoted from the GitHub Primer parity scan (meta/docs/stack #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

StateMeaningSemantic colorIcon
OpenActive issuesuccess (open-green)issue-opened
Closed — completedResolved as donedone (purple)issue-closed
Closed — not plannedClosed without actionneutral (grey)skip/circle-slash

Pull request

StateMeaningSemantic colorIcon
DraftNot yet ready for reviewneutral (grey)git-pull-request-draft
OpenReady / in reviewsuccess (open-green)git-pull-request
MergedMerged into targetdone (purple)git-merge
ClosedClosed unmergeddanger (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).

References