HTMLScreen Readers & Live Regions

Screen Readers & Live Regions

A screen reader is software that converts on-screen content into synthesized speech or braille output. Understanding roughly how it parses your HTML—and testing with a real one occasionally—is one of the highest-leverage accessibility skills you can build, because it exposes gaps that a purely visual review never will.

How Screen Readers Parse a Page
Screen readers don't render pixels—they walk the accessibility tree, a version of the DOM annotated with each element's role, name, and state. That tree is built from:
  • The HTML element itself (a <button> has an implicit role of "button").

  • Its accessible name (visible text, alt text, aria-label, or a linked <label>).

  • Its state (checked, expanded, disabled, invalid, current focus).

  • Its position in the document, including landmarks and heading levels.

This is why semantic HTML matters so much for accessibility: every native element already has a role and behavior baked in. A <nav> is announced as a navigation landmark; an <h2> is announced as "heading level 2." A generic <div> announces nothing at all unless you add ARIA to compensate.

what-gets-announced.html

HTML
<nav aria-label="Primary">
  <ul>
    <li><a href="/">Home</a></li>
    <li><a href="/docs">Docs</a></li>
  </ul>
</nav>

<!-- Announced roughly as: -->
<!-- "Primary, navigation landmark" -->
<!-- "list, 2 items" -->
<!-- "Home, link, 1 of 2" -->
Navigating by Headings and Landmarks
Most screen-reader users don't read a page top to bottom like prose. They jump between headings (often with a single key press) or list every landmark region (<header>, <nav>, <main>, <aside>, <footer>) to get a mental map of the page before deciding where to dive in. A correct, unbroken heading hierarchy isn't a nicety—it's primary navigation infrastructure for these users.
Try it yourself
In NVDA, pressing H jumps to the next heading. In VoiceOver on macOS, VO + Cmd + H does the same. Skipping through headings on your own site is a fast way to find gaps.
A Quick Testing Workflow

You don't need to become a screen-reader power user to catch the most common problems—a five-minute pass with the tool built into your OS surfaces most of them.

Platform

Screen reader

How to start it

macOS

VoiceOver

Cmd + F5 (or Cmd + triple-tap Touch ID)

Windows

NVDA (free)

Download from nvaccess.org, then Ctrl + Alt + N

Windows

Narrator (built-in)

Ctrl + Win + Enter

iOS

VoiceOver

Settings → Accessibility → VoiceOver

Android

TalkBack

Settings → Accessibility → TalkBack

A minimal manual test you can run on any page:

  • Turn on VoiceOver or NVDA and close your eyes (or turn off the monitor).

  • Tab through every interactive element—can you tell what each one does?

  • Jump heading to heading—does the outline make sense out of context?

  • Submit a form with an error—does the screen reader announce what went wrong?

Live Regions: Announcing Dynamic Changes
A screen reader only announces content when it changes focus or when it's told to watch a region for updates. If your JavaScript updates text on the page—a form error, a "3 items added to cart" toast, a search-results count—without moving focus, a screen-reader user gets no indication anything happened. That's what aria-live is for.

aria-live-basic.html

HTML
<div aria-live="polite" id="cart-status"></div>

<script>
  document.getElementById('cart-status').textContent =
    '3 items added to cart';
</script>
When the text inside an aria-live region changes, the screen reader announces the new content automatically—no focus change required.

Value

Behavior

aria-live="polite"

Announces when the user is idle; does not interrupt current speech. Use for most status updates.

aria-live="assertive"

Interrupts immediately. Reserve for urgent, time-sensitive messages like a session timeout.

aria-live="off"

Default for most elements; changes are not announced.

assertive is disruptive
Overusing aria-live="assertive" talks over whatever the user is currently doing. Reach for polite by default and reserve assertive for genuinely urgent messages.
HTML also has two built-in shorthand roles that imply aria-live behavior without you setting the attribute directly:

role-status-alert.html

HTML
<!-- role="status" behaves like aria-live="polite" -->
<div role="status">Saved successfully.</div>

<!-- role="alert" behaves like aria-live="assertive" -->
<div role="alert">Error: connection lost.</div>
The region must exist before it updates
Screen readers only pick up an aria-live region if it was already present in the DOM when the page loaded. Injecting a brand-new aria-live element and its text at the same time is unreliable—render the empty container up front, then fill it in later.
Visually-Hidden Text for Screen Readers Only

Sometimes you need to give a screen reader more context than a sighted user needs on screen—like clarifying that an icon-only button closes a dialog. The standard technique is a "visually-hidden" CSS class: content stays in the accessibility tree but is clipped from the visual layout.

visually-hidden.css

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;
}

visually-hidden-usage.html

HTML
<button type="button">
  <svg aria-hidden="true"><!-- close icon --></svg>
  <span class="visually-hidden">Close dialog</span>
</button>
Never use display: none for this
display: none and visibility: hidden remove content from the accessibility tree too—screen readers skip it entirely. Use the clip-based visually-hidden pattern above instead, which hides content visually while keeping it announced.
Quick Reference

Concept

Use it for

Accessible name

What gets spoken to identify an element

Heading navigation

Jumping between sections of a page

Landmark regions

Getting an overview of the page layout

aria-live="polite"

Non-urgent status updates

aria-live="assertive"

Urgent, interrupting announcements

role="status" / role="alert"

Shorthand for the two live-region types above

.visually-hidden

Extra context for screen readers, hidden visually