Stat tile — accessibility

Keyboard

  • A tile that opens something is keyboard-operable: the component sets role="button", tabIndex=0 and handles Enter and Space. This is the pattern the Deal card and the collapsible Section block header still lack.
  • A tile without onClick is not focusable, which is correct — it is a number, not a control.

ARIA

  • The label and the value are plain text in reading order, so the tile is announced as "label, value".
  • The caption (.stat-cap) is read with the label; the sub-line after the value.
  • The tone is a colour on the number: it must never be the only carrier of meaning, which is why a critical tile also says what it counts.
  • Nothing announces a value change after a refresh.

Focus

  • The clickable tile takes the foundation ring from ds.css, and the sheet adds its own :focus-visible for the rounded corner.
  • A non-interactive tile has no focus state and no tab stop.

Contrast

Computed from packages/ui/src/tokens/tokens.css:

  • Value in ink on --surface-100 — above AA in both themes.
  • Label and caption use muted tones (--fg-muted = 2.85:1 light, 3.63:1 dark) — below AA for text.
  • Tones: reached (positive ink), crit (--critical-ink = 5.37:1 light) and warning (amber) all pass AA as text; muted is deliberately below it because it means "no data".
  • The hairline border is below the 3:1 non-text minimum, as every hairline in the system.

Known limits

  • Labels and captions sit at the muted contrast limit in light theme.
  • Colour is the only difference between tones; the number itself must say what it counts.
  • No live region, so a refreshed value is silent.

Source: docs/stat-tile/stat-tile.a11y.md · GitLab