aria-expanded has four honest jobs left. The rest belong to the platform.
Marcus Osei
Every extra ARIA attribute you type is a promise to a screen-reader user. aria-expanded="false" says: this control opens something, that something is not open right now, and my JavaScript will change this value the moment that changes. When the promise holds, the user gets a clean announcement and knows what happened. When it drifts, they hear the wrong state as they look at an open panel.
Steve Frenzel's new piece on Piccalilli is a map of which of those promises you still have to make in 2026, and which have quietly become the platform's problem instead of yours. His framing is direct: aria-expanded is no longer strictly needed for some of the patterns you were taught to use it on, because the platform now covers them.
Here is the short version, so you can read it as a working policy.
The four patterns where aria-expanded still earns it
Per Frenzel, four collapsible interactive patterns still require aria-expanded on the trigger: menus, navigation, tree views, and combo boxes.
Navigation is the plainest of the four. If a link opens a fly-out with more links inside it, the trigger carries aria-expanded and toggles between true and false. Frenzel's example is a nested <ul> inside a <nav> with aria-labelledby pointing to a hidden label. The parent link carries aria-expanded. He notes there is currently no way to build this pattern without JavaScript, so you are on the hook for keeping the attribute in sync yourself.
A menu is different. Frenzel is careful to say a menu is not navigation. It is a set of application commands, close to a desktop menubar, and the trigger for one needs both aria-haspopup and aria-expanded. If you reach for aria-expanded alone, the assistive tech will announce a disclosure, not a menu, and the user's model of the widget starts wrong.
Tree views inherit the same rule at every expandable branch. Frenzel's example places aria-expanded on each <li role="treeitem"> whose children can collapse, alongside the positional attributes the pattern needs anyway (aria-level, aria-posinset, aria-setsize).
Combo boxes are the fourth. The trigger opens a listbox, so aria-expanded tells the user whether that listbox is currently visible. But Frenzel notes that if the only reason you were building a combo box was to style a <select>, the native element is now a better option. That is one fewer combo box to ship.
Where you should stop reaching for it
The most common misuse Frenzel names is the disclosure widget: a button that toggles a hidden container. His example has the full pattern — a <button> with aria-controls and aria-expanded, plus the JavaScript to flip the attribute — and then his recommendation, which you should read as a hard preference: if that is all your control does, use <details> and <summary> instead. No script. No attribute to keep in sync. The state is the DOM state.
Dialogs are the other big one. A dialog is not "expanded", it is modal, and Frenzel's guidance is aria-modal on the container, not aria-expanded on the trigger. He goes further and shows a <dialog> opened with the new invoker command syntax:
<button command="show-modal" commandfor="my-dialog">
Open dialog
</button>
<dialog id="my-dialog">
<h2>Progressive enhancement</h2>
<button commandfor="my-dialog" command="close">Close</button>
</dialog>
That is a real dialog, wired without JavaScript, and none of it involves aria-expanded.
Tooltips get the same treatment. The Popover API and invoker commands give you a <button command="toggle-popover" commandfor="info"> pointing at a <div popover="auto" role="tooltip">, and once again the attribute you were going to add is redundant.
Tabbed interfaces are worth calling out for a different reason. Frenzel's note is that a tab uses aria-haspopup, not aria-expanded. If you have the former on a trigger and the latter is missing, that is the correct shape.
Read the APG with your eyes open
One aside from Frenzel worth carrying into your next code review: he says the ARIA Authoring Practices patterns are not suitable for production use. Treat the APG as a study of the semantics you are aiming for, then test the result with actual assistive tech. A widget that follows the APG to the letter can still fail the user. A widget with fewer attributes and the right native element often will not.
The checklist for your next PR
- Reach for
<details>and<summary>before you write your first line of disclosure JavaScript. - Keep
aria-expandedon triggers for menus, navigation, tree views, and combo boxes. Addaria-haspopupon the menu trigger; combo boxes may need it too. - Use
<dialog>andaria-modalfor modal dialogs. If you are opening one from a button, look at thecommandandcommandforattributes before you write another click handler. - Reach for the Popover API and invoker commands for tooltips and toggled surfaces.
- Do not ship an APG pattern straight to production without testing it end to end.
Frenzel's verdict is not that aria-expanded is broken. His point is that a shrinking number of widgets still need it, and every extra attribute you write should be one the platform genuinely cannot provide for you.
Source: Piccalilli (piccalil.li)