WCAG 2.1 AA • AODA compliant • Updated Mar 28, 2025
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:
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 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. |
<!-- 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>
<button> for actionable controls.aria-label for icon-only buttons.aria-pressed for toggles and aria-expanded for disclosures.disabled for unavailable actions and style them as inert.<div> or <span> as buttons without full ARIA and keyboard support (role, tabindex, Enter/Space handlers).title attribute for the accessible name.aria-label on icon-only buttons.disabled attribute.aria-disabled on native buttons; use disabled instead.<button>.aria-pressed/aria-expanded in sync with visuals.aria-label so assistive tech announces purpose.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. |