aria-expanded aria-controls for Toggles
Build accessible disclosure and accordion widgets with ARIA.
aria-expanded aria-controls for Toggles is a free HTML Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the HTML Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Toggle Pattern Overview
Toggle controls (accordions, dropdowns, menus) need ARIA to communicate their open/closed state:
aria-expanded— indicates open/closed state of a controlaria-controls— links the control to the element it controls
aria-expanded
aria-expanded communicates whether a controlled element is expanded or collapsed:
<button aria-expanded="false" aria-controls="menu">
Menu
</button>
<ul id="menu" hidden>
<li><a href="/">Home</a></li>
</ul>
<script>
btn.addEventListener('click', () => {
const expanded = btn.getAttribute('aria-expanded') === 'true';
btn.setAttribute('aria-expanded', !expanded);
menu.hidden = expanded;
});
</script>aria-controls
aria-controls references the id of the element that is controlled:
<button
id="details-btn"
aria-expanded="false"
aria-controls="details-panel"
>
Show Details
</button>
<div id="details-panel" hidden>
<p>Additional details go here...</p>
</div>
<!-- Screen reader: 'Show Details, button, collapsed'
After click: 'Show Details, button, expanded' -->Accordion Pattern
Accessible accordion with aria-expanded:
<div class="accordion">
<h3>
<button
aria-expanded="false"
aria-controls="panel-1"
>Section 1</button>
</h3>
<div id="panel-1" hidden>
<p>Panel 1 content...</p>
</div>
<h3>
<button
aria-expanded="false"
aria-controls="panel-2"
>Section 2</button>
</h3>
<div id="panel-2" hidden>
<p>Panel 2 content...</p>
</div>
</div>Dropdown Menu Pattern
Accessible navigation dropdown:
<nav>
<button
aria-expanded="false"
aria-haspopup="true"
aria-controls="products-menu"
>Products</button>
<ul id="products-menu" role="menu" hidden>
<li role="menuitem"><a href="/widget">Widget</a></li>
<li role="menuitem"><a href="/gadget">Gadget</a></li>
</ul>
</nav>aria-haspopup
aria-haspopup hints that activating the control will open a popup:
<button aria-haspopup="menu">File</button>
<!-- Values: true (menu), menu, listbox, tree, grid, dialog -->
<!-- Screen reader: 'File, button, has popup' -->
<!-- Note: aria-haspopup="true" is equivalent to "menu" -->
<!-- Use specific values when the popup type matters -->Details/Summary ARIA Supplement
The native details/summary already communicates expansion state — no ARIA needed:
<details>
<summary>FAQ Question</summary>
<p>Answer goes here.</p>
</details>
<!-- Browser automatically provides aria-expanded
and the disclosure widget semantics -->
<!-- No need to add aria-expanded manually to summary -->CSS for aria-expanded State
Use aria-expanded as a CSS hook:
/* Panel hidden by default: */
[aria-controls] + [hidden] {
display: none;
}
/* Or using aria-expanded on the button: */
[aria-expanded="false"] + .panel {
display: none;
}
[aria-expanded="true"] + .panel {
display: block;
}
/* Rotate arrow icon: */
[aria-expanded="true"] .arrow {
transform: rotate(180deg);
}Keyboard Requirements for Toggles
Toggle components must support keyboard interaction:
- Enter or Space — activate the toggle button
- Escape — close a dropdown or menu
- Arrow keys — navigate within an open menu
Managing Focus After Toggle
After toggling content, manage focus appropriately:
// Accordion: focus stays on the button (usually OK)
// Dropdown menu: move focus to first menu item on open
button.addEventListener('click', () => {
const expanded = button.getAttribute('aria-expanded') === 'true';
button.setAttribute('aria-expanded', !expanded);
panel.hidden = expanded;
if (!expanded) {
// Opening a dropdown: focus first item
panel.querySelector('a, button, [tabindex]')?.focus();
}
});Mobile Considerations
Toggle components on mobile:
- Touch targets must be at least 44×44px (WCAG 2.5.5)
- aria-expanded is supported by mobile screen readers (iOS VoiceOver, Android TalkBack)
- Swipe gestures do not replace keyboard/button activation
Quick Check
What value should aria-expanded have when the controlled section is hidden?
Recap: aria-expanded and aria-controls
Toggle ARIA essentials:
aria-expanded="true/false"— open/closed state of controlaria-controls="id"— links control to its panelaria-haspopup— hints a popup is available- Update aria-expanded on every toggle
- Move focus into opened menu; return to trigger on close
Frequently asked questions
Is the “aria-expanded aria-controls for Toggles” lesson free?
Yes — the full text of “aria-expanded aria-controls for Toggles” is free to read here on the web, and the HTML Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the HTML Academy course, upgrade to CoddyKit PRO.
What will I learn in “aria-expanded aria-controls for Toggles”?
Build accessible disclosure and accordion widgets with ARIA. You practise HTML Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start HTML Academy?
No prior experience is required. HTML Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “aria-expanded aria-controls for Toggles” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this HTML Academy lesson?
Yes. Every HTML Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- aria-expanded aria-controls for Toggles
- aria-selected and Tab Patterns
- Live Regions aria-live aria-atomic aria-relevant
- Testing with Screen Readers