Lesson 09 · Part 2 · Disclosure

Toggling content visibility

Hiding something has two sides: whether eyes can see it, and whether screen readers and the Tab key can reach it. Each hiding method sets those two sides differently. Pick the wrong one and you get ghosts: things you cannot see but can still Tab to, or things you see but a screen reader skips.

In one minute

In plain words

Think of a shop window and a back room. display: none removes the item from the shop entirely. opacity: 0 is like painting the item invisible while it still stands in the aisle: you cannot see it, but you bump into it. aria-hidden is a sign that says "ignore this" to blind customers while sighted ones still see it. The accessibility tree is the list of things the browser tells assistive technology about. Hiding methods decide who gets removed from that list.

1. The hiding matrix: try every method

The same link is hidden six different ways below. For each, check four things: can you see it, does it keep its space, does a screen reader read it, and does Tab reach it. The effects are real, not simulated.

Lab: hide the link

Step 1. Pick a method. Press Tab from the "Before" line and note where focus lands.

Before

After

Focus is on: nothing yet


          
What each method does
QuestionAnswer

visibility: hidden keeps the empty space but removes the control from tab order and screen readers. opacity: 0 hides nothing but the pixels. The "visually hidden" class clips the element to one pixel so sighted users see nothing while screen readers still read it. Never use left: -9999px as a hiding method for focusable things; focus can go off-screen.

2. The aria-hidden trap

aria-hidden="true" removes an element from the accessibility tree but does not remove it from the tab order. A button inside it still takes focus, and the screen reader says nothing, or only "button". This breaks the rule that focusable things must have a name and role (WCAG 4.1.2). Typical cause: an off-screen drawer or a "closed" modal marked aria-hidden while its links still work.

Lab: a ghost button

Step 2. Tab through the area. Switch fixes and see which stay reachable.

Focus is on: nothing yet


          
Fails.

Good uses of aria-hidden="true": decorative icons and emoji ( like this one), duplicated visual text, and the page behind an open modal (though inert is better there). It must never be on or around anything focusable.

3. Native disclosure with details and summary

A disclosure is a control that shows or hides one section. The native <details> element does it with no JavaScript. The <summary> is the clickable label. The browser supplies the role ("disclosure triangle" or "button"), the state (expanded or collapsed), and keyboard support (Enter and Space). Compare three builds of the same "Shipping times" toggle.

Lab: three ways to build "Shipping times"

Step 3. Pick a build, then try it with the keyboard: Tab to it, press Enter or Space.


          
Fails.

Keep the summary text steady (do not change it between "Show" and "Hide"); the state is announced for you. Content inside a closed <details> is not in the accessibility tree and not in the tab order. Browser find-in-page can still open it in some browsers. For your own hidden panels, hidden="until-found" gives the same find-in-page behaviour.

4. A group where one opens at a time

Give several <details> the same name attribute and the browser closes the others when one opens, like an accordion. Support is good in current browsers; where it is missing, they simply behave as independent disclosures, which is still accessible.

Lab: exclusive group

Step 4. Open the first question, then the second. Does the first close?

Can I edit an order?

Until it is packed. After that, contact support.

Do you ship internationally?

Yes, to the countries listed at checkout.


          
Try it.

Exclusive groups are a choice, not a rule. Some users like to compare two answers side by side, so use them only when it helps.

5. Which method for which job?

Lab: pick the job

Step 5. Choose a situation to see the best tool and why.

Pick a situation.

Common mistakes

You seeWhy it is a problemFix
opacity: 0 to close a menuLinks stay in the tab order and the accessibility tree.hidden or display: none after the fade.
aria-hidden around a buttonFocus lands on a control nobody announces.Remove aria-hidden or use inert.
display: none on a label you needScreen readers lose the name too.Use the visually hidden class.
Clickable div toggleNo keyboard, no state.<details> or a button with aria-expanded.
Summary text swaps "Show" / "Hide"Announced as a different control each time.Keep one label; the state speaks.
Animation ignores reduced motionSlide-ins can cause discomfort.Wrap in prefers-reduced-motion.
Try it yourself
  1. In lab 3, build "details / summary", then open it with Enter and with Space.
  2. In lab 1, pick opacity: 0 and press Tab from "Before". Where does focus go, and what do you see?
  3. Turn on a screen reader or use your browser's accessibility panel in devtools and compare what display: none and aria-hidden remove.

Remember

Edit this example in the playground