aria-disabled in Composites, disabled in Forms
MUST: Use `aria-disabled="true"` — not HTML `disabled` — for unavailable menu items, toolbar buttons, tabs, tree items and listbox options: `disabled` drops them out of the tab order and the arrow-key sequence, so users never discover the option exists. `aria-disabled` only changes the announcement, so YOUR handler must make activation a no-op. Keep HTML `disabled` for form controls whose state is already inferable from context.
Keep unavailable menu items, tabs and options focusable so users can discover they exist
<li role="menuitem" tabIndex={-1} aria-disabled="true"
onClick={(e) => { if (isDisabled) return; run(); }}>Move to…</li>Bad
Good
Why it matters
The two spellings of "unavailable" behave completely differently, and picking the wrong one deletes information. HTML disabled makes the control unfocusable, unclickable and silent: it vanishes from the tab order, and any arrow-key handler in a composite widget is forced to skip over it, which is how a menu of six commands quietly becomes a menu of three for anyone not using a mouse.
They never learn Delete or Move to… exist, so they cannot ask why the commands are unavailable or how to unlock them. aria-disabled="true" changes only the announcement — the element stays focusable and stays in the arrow-key sequence, assistive technology announces it as dimmed or unavailable, and it is YOUR handler that must make activation a no-op (the browser will not do it for you, so an aria-disabled button without a guard in its onClick is still live).
Use HTML disabled where the state is already inferable from context — a form submit that is greyed out under a validation summary, a Next button on the last step. Use aria-disabled inside composite widgets: menu items, toolbar buttons, tabs, tree items, listbox options. Be aware of the overlap: "Never Put a Tooltip on a disabled Button" also reaches for aria-disabled in its good example, but its subject is tooltips and hover targets; this principle is about discoverability inside a composite, and it pairs with the one-tab-stop roving-tabindex rule — that arrow-key loop is exactly what disabled breaks.