Video examples

iOS Voiceover Safari

Android Talkback Chrome

Windows Jaws Chrome

Windows NVDA Chrome

Code examples

Use semantic HTML

This semantic HTML contains all accessibility features by default.


Focusable disabled button

The preferred method is to use aria-disabled="true" so screen reader users can find the button, click submit and be notified of errors in the form.

<button aria-disabled="true">

Fully disabled button

A button that uses the disabled attribute will not be focusable, but it is still discoverable by the screen reader while browsing.

<button disabled>

When you can’t use semantic HTML

This custom button requires extra attributes and JS event listeners. Adding tabindex="0" makes it focusable.

<div role="button" tabindex="0">

When there is no inner text

As a last resort, aria-label can be used.

<div role="button" tabindex="0" aria-label="Continue">
  <!-- icon -->

When there are repeating buttons

Sometimes the design will call for multiple buttons with the same text label. In a case like this, aria-label can be used to name each control’s purpose.

<button aria-label="Edit payment date">
<button aria-label="Edit payment amount">

Developer notes


  • Inner text should describe the purpose of the button.
  • aria-label="Button purpose" can also be used (as a last resort)


  • Native button identifies as button by default
  • Use role="button" for custom elements


  • Use aria-haspopup="true" for menu, listbox or modal
  • aria-controls="popupId" is not well supported


  • Toggle buttons aria-pressed="true/false"
  • Menus or expanders use aria-expanded="true/false"
  • Use the disabled state for inactive buttons
  • Use aria-disabled="true/false" state for inactive custom elements


  • Focus must be visible
  • Custom elements need tabindex="0" to be focusable