[dialog] Rationale for `aria-expanded` on `Dialog.Trigger` (modal dialogs)
- Dominant language
- TypeScript
- Stars
- 10.9k
- Forks
- 543
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 101
Description
## Summary
`Dialog.Trigger` renders both `aria-haspopup="dialog"` and `aria-expanded` (reflecting open state). I'd like to understand the reasoning behind including `aria-expanded` on a modal dialog trigger, and whether it's something the team has deliberately considered vs. inherited from the shared trigger primitive.
## Context
This came out of an accessibility audit. The finding was:
> `aria-expanded` on the trigger button causes a misleading "collapsed" announcement. The trigger has `aria-expanded="false"`, which causes NVDA to announce something like "Open dialog, button, collapsed, opens dialog" — a confusing combination. `aria-expanded` is intended for widgets that expand and collapse inline content such as accordions and dropdowns. Opening a dialog is not inline content expansion. `aria-haspopup="dialog"` alone is the correct and sufficient attribute for a dialog trigger, and `aria-expanded` should be removed.
While a modal is open, focus is trapped inside it and the trigger is inert/unreachable, so `aria-expanded="true"` is effectively never announced in context. The only states a user actually encounters are `aria-expanded="false"` on initial render and again on close — i.e. the "collapsed" announcement, which is the confusing one.
So the attribute seems to only ever surface in the situation where it reads as noise, at least for the modal case. For **non-modal** popups (where the trigger stays in the tab order alongside the open content) `aria-expanded` clearly still makes sense.
## Questions
1. Is `aria-expanded` on `Dialog.Trigger` a deliberate choice, or a consequence of `Dialog` sharing a trigger primitive with `Popover` / `Menu` / `Select` etc.?
2. Has the modal vs. non-modal distinction come up in this context before?
3. Would you consider dropping `aria-expanded` for modal dialog triggers (or making it conditional on modality), or is there a rationale for keeping it that the audit finding overlooks?
Happy to open a PR if there's an agreed direction. Mostly want to understand the intent before we override it downstream.
Contributor guide
Research direction
Start by tracing Dialog.Trigger and the shared trigger primitive used by Popover, Menu, and Select, then compare how modal and non-modal triggers expose ARIA state. Review the accessibility audit behavior with NVDA and determine whether modal dialog triggers should omit aria-expanded; done means the team has an agreed direction and any resulting behavior is covered by the relevant component tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- accessibility, frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100