Standards · ARIA

Role Widget

button

Marks an element as a button — a control that triggers an action when activated. Use the native HTML <button> element first; only reach for role="button" on a <div> or <span> when there is no way to use the native element.

When to use

Almost never — use the native <button> element. The native element handles focus, the space and enter key activations, the disabled state, and form-submission semantics for free. Reaching for role="button" on a <div> means you have to reimplement all of that, and most authors don’t.

The legitimate cases for role="button" are narrow:

  • You’re constrained by a third-party design system that ships non-button components.
  • You’re authoring inside an environment where <button> is unavailable (some legacy CMS templates).
  • You’re upgrading a <div> for accessibility in the short term while planning a refactor.

If you do use role="button", you must also:

  • Make the element focusable with tabindex="0".
  • Wire up keydown for both Enter and Space (with event.preventDefault() on Space to stop the page scrolling).
  • Manage the disabled state yourself via aria-disabled="true" and prevent click handlers from firing.

Toggle buttons

If the button is a toggle (mute / unmute, play / pause, follow / unfollow), set aria-pressed to "true" or "false". Screen readers announce the state along with the label: “Mute, toggle button, not pressed”.

Common failures

  • <div onclick="…">Submit</div> — not focusable, not keyboard-operable, no role. Mouse users can use it; nobody else can.
  • <a href="#" onclick="…"> masquerading as a button. The browser treats it as a link, the SR announces it as a link, the user expects navigation.
  • role="button" without tabindex="0" — the screen reader announces “button” but the keyboard cannot reach it.
  • Custom buttons that respond to Enter but not Space.
  • Buttons with no accessible name — icon-only buttons missing aria-label are the single most common failure axe-core catches.

Example

<!-- Preferred -->
<button type="button" aria-pressed="false">Mute</button>

<!-- Only when <button> is impossible -->
<div
  role="button"
  tabindex="0"
  aria-pressed="false"
  onclick="toggleMute()"
  onkeydown="if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); toggleMute(); }"
>
  Mute
</div>