Skip to content

Accessibility

The main button is the primary call to action — a native <button> when the action happens in place, or an <a> styled as a button when it navigates elsewhere. It follows the WAI-ARIA Button pattern and meets WCAG 2.1 AA. An accessible button hinges on three things: a clear text label, the correct native semantics, and state that assistive technology can read — so its purpose and status are clear whether the user sees it, hears it, or tabs to it.

  • All button states — rested, hover, active, disabled, focus — must maintain accessible contrast on every supported surface, in both light and dark contexts. Source: WCAG 1.4.3 Contrast (Minimum).
  • Hover, focus, and pressed states must be distinguished by more than colour alone — pair the colour change with a border, shadow, or icon / text emphasis. Source: WCAG 1.4.1 Use of Color.
  • Focus styles must stay visible, meet contrast requirements on every supported surface, and be clearly distinguishable from hover; never remove the browser’s default outline without an accessible replacement. Source: WCAG 2.4.7 Focus Visible.
  • A disabled button may sit below the 4.5:1 text-contrast threshold because it is non-interactive, but it must stay visually recognisable — aim for a clear visual separation from its enabled state. Source: WCAG 1.4.3 Contrast (Minimum).
  • Use semantic colour and focus tokens (e.g. foreground/neutral/default and the global focus token) rather than fixed values, so the button adapts correctly across themes and surfaces.
  • Keep the interactive target at least 44 × 44 px for comfortable touch use, with 24 × 24 px the absolute floor. When the visual button is smaller, add invisible padding or spacing to reach it — the same rule across all sizes (SM, MD, LG). Source: WCAG 2.5.8 Target Size (Minimum).

Use the native <button> element for actions — submitting, toggling, opening a dialog — and an <a> for navigation. Both take .tng-button styling, but only <button> carries the implicit button role and responds to Space; a <div onclick> has neither a role nor keyboard operation, and <a href="#"> announces as a link — so neither is an acceptable substitute. A native <button> is reached with Tab and activated with Enter or Space for free.

The accessible name comes from the button’s text, so every main button carries a visible label (icon-only controls live in the Media Button family) — mark decorative icons aria-hidden="true" so they stay out of the accessibility tree. Toggle, disclosure, and disabled states each have their own wiring: prefer the native disabled attribute over aria-disabled, and reach for aria-pressed or aria-expanded only when the button is a toggle or a disclosure. The per-element roles, names, and states are in the Labelling elements section below.

Give every element the role, name, and state assistive technology needs.

Button

A native <button> carries the implicit role="button"; keep an <a> that navigates as a real link rather than bolting on role="button", so it announces correctly. The accessible name comes from the button’s text content — keep that label clear and action-led, and mark any icon aria-hidden="true" so it doesn’t double the announcement.

Toggle state

For an on / off toggle button, set aria-pressed="true" / "false" and keep it in sync with the pressed state, so assistive technology announces the button as pressed or not pressed.

Disclosure state

When the button shows or hides a region — a menu, panel, or dialog — set aria-expanded="true" / "false" to reflect whether that region is currently open.

Disabled

Prefer the native disabled attribute: it removes the button from the tab order and communicates the state automatically. Only when a disabled button must stay focusable — to surface a tooltip explaining why — use aria-disabled="true" instead, and block activation in JavaScript.

Source: WCAG 4.1.2 Name, Role, Value.