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

1) #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
Try it in the editor →

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.

Learn JavaScript in the Browser for free

20 short lessons with real code and instant checks.

See the whole course →