ARIA in Practice · 5 / 8
lesson 5

Hiding content thoughtfully

Four ways to hide things — each one says something different to a screen reader.

~ 15 min read·lesson 5 of 8
0 / 8

"Hide this." Sounds simple. In practice you have at least four mechanisms, and they are not interchangeable. Each one tells a different story to the browser, to keyboard users, to screen readers, and to search engines.

This lesson lines them up side by side so you can pick the right one without guessing. We'll cover display: none, hidden / visibility: hidden, aria-hidden, and the .visually-hidden (often called .sr-only) utility class.

display: none (and visibility: hidden)

Setting display: none removes the element from the layout tree. The element doesn't render, doesn't take up space, isn't focusable, and is not announced by screen readers. From an accessibility perspective, it's as if the element didn't exist.

visibility: hidden is similar but reserves space — the element's box is still there, just invisible. It also is not announced and is not focusable.

Use these when something is genuinely not part of the page right now. A closed modal. A collapsed accordion panel that hasn't been opened yet. The previous step of a multi-step form.

display-none.css
/* Genuinely not part of the page right now */
.modal[aria-hidden="true"] {
display: none;
}

The HTML hidden attribute

<div hidden> is a built-in attribute that the browser's user-agent stylesheet maps to display: none. Mechanically it's the same as the CSS rule, but it has the advantage of being expressed in HTML — easier to find, easier for tooling to reason about, and harder for a stray CSS rule to override accidentally.

hidden-attribute.html
<section id="step-2" hidden>
...
</section>

Treat hidden as a synonym for display: none in terms of what it does to assistive tech. Both remove the element from the accessibility tree.

aria-hidden

aria-hidden="true" removes an element from the accessibility tree only. Visually it stays exactly where it was. Sighted users see it; screen readers don't.

Use this for genuinely decorative content that's already conveyed elsewhere:

decorative.html
<button>
<svg aria-hidden="true" focusable="false">...</svg>
Save
</button>

The icon is decorative — the word "Save" already names the button. Hiding the SVG from screen readers prevents announcements like "image, save".

The danger zone — covered in lesson 1 but worth repeating — is putting aria-hidden="true" on something that's still focusable. The user lands on it with Tab and the screen reader has nothing to say. Either the focus needs to go away (no tabindex, not a focusable element type) or the aria-hidden does.

Watch out

Never put aria-hidden="true" on a focusable element or any container that has focusable descendants. Every browser's accessibility tester flags this. It is the bug.

There's a sister attribute, inert, that's increasingly the better tool for this case: it hides content from assistive tech and removes it from the tab order, in one go. Reach for inert on the rest of the page when a modal opens, instead of papering over the gap with aria-hidden.

The .visually-hidden utility

Sometimes you want the opposite — content that's invisible to sighted users but announced by screen readers. Use cases include:

  • A "Skip to main content" link that only appears on focus.
  • An icon-only button where you'd rather have hidden real text than rely on aria-label.
  • Extra context for a control: "Edit (article: How to bake)".

The standard CSS class looks like this:

visually-hidden.css
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}

The element exists in the layout tree (so screen readers see it), but it occupies one pixel and is clipped, so sighted users don't. Don't use display: none here — that would hide it from screen readers too, defeating the point.

visually-hidden-usage.html
<button>
<svg aria-hidden="true">...</svg>
<span class="visually-hidden">Delete</span>
</button>

That button announces as "Delete, button" — same as aria-label="Delete" would, but the name is real DOM text. Translation tools see it. Voice users can target it. Some teams prefer this pattern for exactly that reason.

visible hidden announced not announced normal text (do nothing) .visually-hidden clipped to 1px aria-hidden="true" decorative SVG display: none hidden / inert
Each method places the element somewhere different on the visible-vs-announced grid.

Decision flow

When in doubt, walk the tree:

  1. Should sighted users see it? Yes → keep it visible. No → step 2.
  2. Should screen-reader users hear it? Yes → use .visually-hidden. No → step 3.
  3. Is it temporarily out of scope (modal closed, step not active)? Yesdisplay: none / hidden / inert.
  4. Is it purely decorative (icon next to a text label, repeated content)? Yesaria-hidden="true" (and confirm nothing inside is focusable).
Tip

If you find yourself toggling aria-hidden on big interactive sections, look at inert instead. inert hides from assistive tech and removes focusability — fewer chances to miswire it.

Try it yourself

check your understanding
You want a "Skip to main content" link visible only when keyboard-focused, but always announced. Which approach?
check your understanding
Which combination is a bug?
check your understanding
What's the difference between display: none and aria-hidden="true"?
check your understanding
You want to disable interaction with the rest of the page while a modal is open, hiding it from both keyboard and screen reader. The most modern primitive is:
check your understanding
An icon-only "Edit" button uses <span class="visually-hidden">Edit</span> next to an SVG with aria-hidden="true". What does the screen reader announce?
← prevnext lesson →
KeepLearningcertificate
for completing
ARIA in Practice
0 of 8 read