Aria-haspopup and/or aria-expanded
First posted on March 21, 2026
Table of Contents
When to use aria-haspopup and when to use aria-expanded? When to use one and when to use both? Let’s find out!
Introduction
aria-haspopup is used to indicate that an element triggers a popup, while aria-expanded is used to communicate its state: open (true) or closed (false).
At first glance, it looks like they should always be used in tandem, and it is true in most cases, but there are a couple of exceptions.
To understand what these are, let’s take a look at the available values for aria-haspopup:
menulistboxtreegriddialogtrue
As you can note, all these map to specific rolesFootnote 1, with the only exception of the true value.
One would expect it to be some sort of wildcard, but the true value unexpectedly falls back to the menu value for backward compatibility reasons (opens in a new window), which is quite misleading. In practice, it’s better to avoid it and opt for the explicit values instead.
But what if the popup doesn’t match any of these roles?
That’s where aria-expanded comes in. It works with any popup type and can be used on its own when aria-haspopup doesn’t apply. When it does apply, you can safely use both.
An exception: modal dialogs
There’s just one case in which it isn’t really of much use, and that is with modal dialogs.
When a dialog is open, its trigger shouldn’t be reachable, so the state is implicit: either you’re inside the dialog (open) or outside it (closed). In this case, aria-expanded adds little value.
What about tooltips?
Why is tooltip excluded from the list of available values? MDN explains (opens in a new window):
A tooltip is not considered to be a popup […], as it is not interactive.
Interactivity is what qualifies all the roles supported by aria-haspopup.
TL;DR
- Use both for interactive popups with a matching
aria-haspopupvalue (menu,listbox, etc.); - Use only
aria-haspopupfor dialogs; - Use only
aria-expandedfor popups without a matching role (e.g. generic popups or tooltips).
I hope this was helpful. Until next time, be (and code) well!