aria-expanded and aria-controls
aria-expanded says whether a disclosure is open, while aria-controls identifies the panel that its button operates.
See it
What it is
aria-expanded and aria-controls describe the two halves of a disclosure. aria-expanded='false' or 'true' exposes the controlled content's current closed or open state on the button. aria-controls points from that button to the id of the panel it operates.
Use the pair on accordions, disclosure buttons, comboboxes, and menu buttons when one control reveals or collapses another element. Keep aria-expanded on the control, not on the panel, and update it in the same code path that changes the panel's visibility.
The attributes do not perform the interaction. aria-controls does not open anything, aria-expanded does not hide anything, and neither adds keyboard behavior. A stale aria-expanded='false' on a visibly open menu is worse than no state because it gives assistive technology the wrong answer.
Weight the two differently. aria-expanded is broadly supported and does real work. aria-controls is mostly ignored: JAWS is the main screen reader that lets a user jump to the controlled element from it, so treat it as useful metadata rather than navigation your users will get.
Ask AI for it
Turn this trigger and panel into a disclosure using the WAI-ARIA Authoring Practices Disclosure Pattern. Use a native button with aria-expanded='false' and aria-controls set to the panel's unique id. On click, Enter, or Space, toggle the panel's hidden state and update aria-expanded in the same state update so the visual and accessible states cannot drift apart. Keep focus on the button when the panel opens or closes, preserve the panel in logical DOM order, and give the button a visible label that names what it reveals.