aria-expanded, live regions & focus management
Accessible dynamic interfaces
Lesson 11 of 20 · 13 min · Module 3: State, storage and accessibility
When content appears, disappears or changes without a page load, people who use screen readers or keyboards need to be told. Three small habits cover most cases.
Start this lesson →Free. No installation: you write and run the code in your browser, and it is checked automatically.
By the end, you’ll be able to…
- Keep aria-expanded in sync with visibility
- Announce changes with a live region
- Move focus deliberately when content opens and closes
The idea
A button that shows and hides a section keeps aria-expanded in sync with it. Messages placed in a live region, an element with role="status", are announced automatically. When an action opens something new, move focus there with element.focus(); when it closes, return focus to the button that opened it.
button.addEventListener('click', () => {
const open = panel.hidden;
panel.hidden = !open;
button.setAttribute('aria-expanded', String(open));
});
01State that everyone can perceive
Sighted users see a panel appear; screen reader users hear "Show details, button, collapsed" and then "expanded". aria-controls links the button to the panel it controls.
02Live regions speak up
Text inserted into an element with role="status" is read out politely after the current announcement. The element must exist on the page before its text changes, which is why #status is in the HTML from the start.
<p id="status" role="status"></p>
<!-- later: status.textContent = 'Saved' → announced -->
03Focus is a cursor for the keyboard
If a form opens but focus stays on the button, keyboard users must hunt for it. Moving focus into new content, and back afterwards, keeps them oriented.
Your turn
#toggle shows and hides #details: keep its hidden property and the button’s aria-expanded in sync, and switch the button text between Show details and Hide details. 2) #rename shows #rename-form and moves focus to #new-name. 3) When the form is submitted, prevent the default, put the new name in #title, hide the form, write Renamed to plus the name in #status, and move focus back to #rename.What the checks look for
- The details start hidden and collapsed
- The toggle opens the details and says so
- A second click closes them again
- Rename opens the form and focuses the input
- Saving renames the project and announces it
- Focus returns to the Rename button
Take this with you
Sync aria-expanded, announce with role="status", and move focus on purpose.
Go a little further
Close the rename form with the Escape key and return focus to the Rename button.