ARIA property
aria-haspopup
Says this control opens something, and what kind of thing it opens. A menu, a dialog, a listbox.
It warns people before they activate the control that something is about to appear, and says what shape it takes. It does not open anything, and it does not track whether the popup is currently open. That second part is aria-expanded's job.
Which roles may carry aria-haspopup
- Value
- token
- Filed as
- A property, which is how ARIA files it and not a rule about how often it changes.
- Roles that may carry it
application,button,combobox,gridcell,link,menuitem,slider,tab,textbox,treeitem- Roles that inherit it
columnheader,menuitemcheckbox,menuitemradio,rowheader,searchbox
Those lists are not advice. Browsers are required to ignore a non-global attribute sitting on a role that does not support it, so aria-haspopup on the wrong element is not weak, it is absent. You can read it in the DOM and nobody using a screen reader can.
Every role above comes from the specification's own list for this attribute, checked name for name. The normative definition stays with the W3C, in the aria-haspopup section of the ARIA specification.
Keeping aria-haspopup true
There is little to update here and one trap worth knowing, because this attribute runs the opposite way from the other token ones. Where aria-current and aria-invalid treat a value they do not recognise as true, browsers are required to treat an unrecognised aria-haspopup as false, an empty string included. So a typo does not leave you with a vague popup, it leaves you with none. The one legacy value that still works is true, which browsers have to read as menu, so a control opening a dialog and saying true is telling people to expect a menu. Its global use was deprecated in ARIA 1.2, which means it belongs on roles that support it rather than on anything you like.
How aria-haspopup gets checked
There are test rules that check an ARIA attribute is one that exists, is allowed on the role underneath it, and carries a value of the right type. What they map to is ARIA's own author requirements rather than any WCAG criterion, so a misplaced attribute breaks ARIA without being a WCAG failure by itself. It becomes one under 4.1.2 Name, Role, Value the moment the missing or wrong value means the control's state cannot be worked out programmatically, which is what usually happens next.
Nothing automated catches the failure this page is about. A stale value is a valid value, on a permitted role, with the right type. It is only wrong about the world.
Attributes you will meet alongside aria-haspopup
- aria-activedescendant Points at the item inside a composite widget that is currently active, when focus stays on the container.
- aria-autocomplete How a text field predicts what you are typing.
- aria-disabled Says a control is present but not available. Unlike the disabled attribute, it stays focusable, so people can still find out it is there.
- aria-errormessage Points at the message explaining why this field is invalid. Only meaningful while aria-invalid is set.
- aria-expanded Whether the thing this control opens is currently open.
- aria-invalid Says a field's value has failed validation.
- aria-multiline Whether a text field takes more than one line, which changes what Enter does.
- aria-orientation Whether a widget runs horizontally or vertically, which decides which arrow keys move through it.
Every ARIA state and property · Every ARIA role · ARIA explained