Button — accessibility

Keyboard

  • Native <button>: Tab moves focus, Enter and Space activate.
  • disabled removes the button from the tab order (native behaviour; pointer-events: none is added for the mouse).
  • loading sets disabled, so a running action cannot be triggered twice and the button leaves the tab order until the action finishes.
  • A kbd hint only describes a shortcut; the shortcut itself must be wired by the screen (for example Esc closes the dialog, ⌘↵ submits).

ARIA

  • No role needed — the element is a native <button>.
  • loading renders aria-busy="true"; the label stays in the DOM (opacity 0, not visibility: hidden), so screen readers still read the action name.
  • The kbd hint is aria-hidden="true" — it is a visual hint, not part of the accessible name.
  • Icon-only usage is not supported here — use Icon button with aria-label.
  • Pass type="button" inside forms unless the button submits; the component does not set a default type.
  • Default type="button" (acrm !4067): the button never submits a surrounding form by accident; a form's submit button carries type="submit" explicitly, so Enter in a field submits only where the author meant it.

Focus

  • Focus ring comes from the foundation rule in ds.css: :where(button, …):focus-visible { outline: 2px solid var(--accent); outline-offset: 1px }.
  • The ring follows the button's own --radius-sm and does not change resting elevation.
  • No button-specific focus style; do not add outline: none.

Contrast

Ratios computed from packages/ui/src/tokens/tokens.css (WCAG 2.x relative luminance):

  • primary label: --fg-on-accent #ffffff on --accent #0072f5 = 4.44:1 (light and dark); hover on --accent-press #0062d1 = 5.73:1.
  • default label: --fg #18191b on --surface-100 #ffffff = 17.59:1 (light); #eceded on --surface-50 #232529 = 13.09:1 (dark).
  • ghost label on canvas: 17.59:1 (light), 14.53:1 (dark).
  • danger label: #ffffff on --critical #e5484d = 3.91:1 — passes AA for large/bold text only; the 13px 500 label is below AA 4.5:1 for normal text. Known limit.
  • Focus ring --accent on canvas: 4.44:1 (light), 3.83:1 (dark) — above the 3:1 non-text minimum.

Known limits

  • tone="muted" label (--fg-secondary = ink-500 #7d8184) is 3.93:1 on white, below AA 4.5:1 for normal text. It is the same tone as every secondary text in the DS (meta, labels, hints), so the button is not an exception; it is a palette-wide finding (AD 28 Sep 2026) recorded in AUDIT-tlacitka-2026-09-26.md → „Nález pro design tokeny". A shift of ink-500 goes to the owner separately.
  • danger label contrast 3.91:1 is below AA for normal text (see Contrast).
  • disabled uses opacity 0.5; the disabled label contrast is not guaranteed (WCAG exempts disabled controls).
  • loading gives no text announcement beyond aria-busy; long-running actions should announce completion in the screen (toast, status text).
  • The kbd hint is hidden from assistive technology; shortcut discoverability for screen-reader users depends on the screen's own documentation.

Source: docs/button/button.a11y.md · GitLab