Button Component — Accessibility Specification

WCAG 2.1 AA • AODA compliant • Updated Mar 28, 2025


About this element

The <button> HTML element represents a clickable control that triggers an action within a page or application. Buttons typically perform actions (e.g., submitting a form, opening a dialog, toggling a feature) rather than navigating to a new resource.

Where and how is it used? Buttons are ubiquitous across digital interfaces:

Accessibility Requirements

This section outlines WCAG criteria, ARIA roles and attributes, keyboard accessibility, and focus management.

Requirement WCAG Success Criteria Description for Designers & Developers
Keyboard Operability 2.1.1 Keyboard (Level A) What’s required: All button functionality must be operable via keyboard.
Design: Buttons look interactive and include visible focus styles.
Dev: Focusable with Tab; activate with Enter or Space. Disabled buttons are not focusable.
Focus Indication 2.4.7 Focus Visible (Level AA) What’s required: A clear focus indicator appears on keyboard focus. Never remove outlines unless replaced with an equal or better custom style.
Role & State Communication 4.1.2 Name, Role, Value (Level A) What’s required: Expose role “button”, accessible name, and states (pressed, expanded, disabled). Use aria-pressed for toggles, aria-expanded for disclosures, and native disabled when unavailable.
Contrast & Visibility 1.4.3 Contrast (Minimum) (Level AA) Button text/icon contrast ≥ 4.5:1 against background; focus indicator is also clearly visible.

ARIA Roles and Attributes

ARIA Role/Attribute Component/Element Used On Purpose & Usage
<button> Interactive element (implicitly role="button") Purpose: Native element with semantics and keyboard support.
Usage: Prefer native <button>; no explicit role needed.
role="button" <div> or <span> (custom controls) Purpose: Declares a non-semantic element as a button.
Usage: Add tabindex="0" and key handlers for Enter/Space. Only when native button can’t be used.
aria-pressed="true|false" Toggle buttons Conveys on/off state (e.g., Play/Pause). Keep visual label and state in sync.
aria-expanded="true|false" Disclosure buttons Announces expanded/collapsed state for accordions, menus, dropdowns.
aria-disabled="true" Non‑native buttons (e.g., <a role="button">) Communicates “disabled” while remaining in DOM. Remove from tab order (tabindex="-1") and prevent activation in JS.
aria-label / aria-labelledby Icon‑only buttons Provides accessible name when no visible text exists.

Implementation Guidelines

Code Examples (HTML, ARIA, JS)

<!-- Basic button -->
<button type="submit">Submit Form</button>

<!-- Toggle button with aria-pressed -->
<button type="button" aria-pressed="false" id="toggleBtn">Mute</button>
<script>
  const b = document.getElementById('toggleBtn');
  b.addEventListener('click', () => {
    const on = b.getAttribute('aria-pressed') === 'true';
    b.setAttribute('aria-pressed', String(!on));
    b.textContent = on ? 'Mute' : 'Unmute';
  });
</script>

<!-- Icon-only button -->
<button type="button" aria-label="Delete item">
  <svg aria-hidden="true" focusable="false" width="20" height="20"><path d="..."/></svg>
</button>

DO’s

Don’ts

Common Pitfalls

Testing Checklist

Validate with Assisstive Technologies like NVDA/JAWS/VoiceOver and keyboard on Chrome/Firefox/Safari browsers.

Test Item WCAG Criteria Pass Criteria
Keyboard Focus 2.1.1 Keyboard (A) Button is reachable via Tab. Disabled buttons are skipped.
Keyboard Activation 2.1.1 Keyboard (A) Pressing Enter or Space activates the focused button.
Focus Indicator 2.4.7 Focus Visible (AA) Visible outline/highlight is clear and not removed.
Accessible Name 4.1.2 Name, Role, Value (A) Meaningful name present (visible text or ARIA label). Icon-only buttons have aria-label.
Role & State 4.1.2 Name, Role, Value (A) Role “button” announced; states (pressed/expanded/disabled) conveyed correctly.
Color Contrast 1.4.3 Contrast (AA) Text/icon contrast ≥ 4.5:1; focus style is visible.