Skip to content
Pandus

Disabled buttons and accessibility

The greyed-out "Add to cart" until a size is chosen, the "Place order" button that stays disabled until every field is filled — disabled buttons are everywhere on online shops. WCAG has a specific exemption for them, but that does not make them a good idea in every case.

Updated October 14, 2026 · 6 min read · How we write and check our guides

This page covers the rules, the two ways to disable a button and better alternatives. It is part of the accessible UI patterns series.

What WCAG says

  • Contrast exemption. 1.4.3 Contrast (Minimum) exempts "text or images of text that are part of an inactive user interface component", and 1.4.11 Non-text Contrast exempts inactive components too. W3C defines an inactive component as one that "is visible but not currently operable" and gives a disabled submit button as the example. The Understanding document explains that the exemption exists because no single good way to show disabled controls has been found.
  • Name, role, state. 4.1.2 Name, Role, Value: the disabled state must be exposed in code, not only by grey colour.
  • Instructions. 3.3.2 Labels or Instructions: if the user must do something before a button works, say so.
  • Errors. 3.3.1 Error Identification: a disabled submit button is not an error message. The user still needs to learn in text what is wrong.

So low contrast on a disabled button does not fail WCAG — but a disabled button nobody can understand may still fail the criteria above and certainly costs sales.

disabled vs aria-disabled

disabled attribute aria-disabled="true"
Works on Native form controls: button, input, select, textarea, fieldset Any element with an interactive role
Can be activated No, the browser blocks it Yes — your script must ignore the action
In the tab sequence No Yes
Screen reader announces "unavailable"/"dimmed" Yes Yes

The APG keyboard guide says "browsers remove HTML input elements with the disabled attribute from the tab sequence". Where users need to discover a disabled element — the APG mentions menu items, tabs, listbox options and tree items — it uses aria-disabled="true" so the element stays focusable. The APG button pattern also says that when a button's action is unavailable, "the button has aria-disabled set to true".

The practical rule: use disabled when it does not matter that the button is skipped; use aria-disabled when users need to find the button and learn why it does not work.

Code example

<!-- Discoverable: stays in the tab order, the reason is announced -->
<p id="size-hint">Choose a size to add this item to your cart.</p>
<button type="button" id="add" aria-disabled="true" aria-describedby="size-hint">
  Add to cart
</button>

<script>
  const add = document.getElementById('add');
  add.addEventListener('click', (event) => {
    if (add.getAttribute('aria-disabled') === 'true') {
      event.preventDefault();          // block the action yourself
      document.getElementById('size').focus();
      return;
    }
    addToCart();
  });
  // When a size is selected: add.setAttribute('aria-disabled', 'false');
</script>

<!-- Fine to skip: a native disabled control the user does not need to reach -->
<button type="button" disabled>Previous page</button>

Style [aria-disabled="true"] so it looks unavailable — the browser will not do that for you.

Better alternatives

  1. Keep "Place order" enabled. When it is pressed with missing data, show error messages in text, move focus to the first error or an error summary. See form validation and errors.
  2. Say what is needed next to a disabled button, in visible text, not in a hover tooltip.
  3. Do not hide an unavailable option without explanation — a sold-out size can stay in the list, marked "sold out".

Keyboard interaction

Key disabled button aria-disabled button
Tab Skips the button Moves focus to it; screen reader says it is unavailable and reads the description
Enter / Space Nothing Nothing happens — or the script moves focus to what is missing

Common mistakes on online shops

  • "Add to cart" disabled until a variant is chosen, with no visible hint. Keyboard users never reach the button and do not know why.
  • The checkout "Pay" button disabled until all fields pass validation, while the fields show no error messages.
  • A button that looks disabled but is not (grey style only), or one that is disabled in code but looks active.
  • aria-disabled="true" without a script guard, so the button still submits.
  • Disabled state shown only by lower opacity while the reason appears in a title tooltip.
  • Unreadably light disabled text for important information such as "Out of stock". The text may be exempt from contrast, but the information should also be available in readable text.

What automated checks catch vs manual testing

Automated (axe-core rule) What it finds
color-contrast Low-contrast text; disabled controls are skipped, as WCAG exempts them
button-name Buttons without a name, disabled or not
aria-valid-attr-value aria-disabled with an invalid value, aria-describedby pointing to a missing ID
aria-allowed-attr ARIA attributes not allowed on the element's role

All are cards in our rule library. Manual testing: try to complete the form or the product choice with the keyboard only, check that every disabled control has a visible reason, and check with a screen reader that the state and the reason are announced. The contrast checker helps choose a disabled style that stays readable.

Run the free one-page check. It is an automated check, not a full audit.

Frequently asked questions

Do disabled buttons need to meet WCAG contrast requirements?

No. Both 1.4.3 Contrast (Minimum) and 1.4.11 Non-text Contrast exempt inactive user interface components, which W3C defines as visible but not currently operable. A disabled submit button is the example W3C gives.

What is the difference between disabled and aria-disabled?

The HTML disabled attribute makes a native control inoperable and removes it from the tab sequence. aria-disabled="true" only tells assistive technology the control is unavailable; it stays focusable and you must block the action in your script.

Is it bad to disable the submit button until the form is valid?

It often causes problems: users cannot find out what is missing, and keyboard users cannot even reach the button. Keeping it enabled and showing clear error messages on submit usually works better.

How do I explain why a button is disabled?

Put the reason in visible text near the button, for example "Choose a size to add to cart", and connect it with aria-describedby. Do not rely on a tooltip on hover.

Can an automated check test disabled buttons?

Contrast checks skip disabled controls, as WCAG does. Automated rules check that aria-disabled has a valid value and that buttons have a name. Whether users understand why a button is unavailable needs a manual test.

Sources

  • W3C, Understanding 1.4.3 Contrast (Minimum): https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html
  • W3C, Understanding 1.4.11 Non-text Contrast: https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html
  • W3C WAI, APG Developing a Keyboard Interface (focusability of disabled controls): https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/
  • W3C WAI, APG Button pattern: https://www.w3.org/WAI/ARIA/apg/patterns/button/

Guides and tools