Screen-Reader Testing
A screen reader does not see your page — it reads the accessibility tree your markup builds. Test like a screen-reader user and you find the failures that the eye, and the keyboard, both miss.
1 The Hook
A Te Whatu Ora team built a clean, modern page listing test results. Visually it was excellent — clear headings, a tidy table, friendly icons. A tester who used a screen reader every day spent ten minutes with it and came back with a page of defects no sighted reviewer had seen.
The headings were not headings. The designer had styled bold <div> text to look like headings, so the screen reader’s heading shortcut — the way these users skim a page — found nothing and the user had to wade through every word in order. The status icons, a green tick and a red cross, had no text alternative, so a critical “action required” result was announced as just “image”. The “Download” links were every one of them simply “Download”, with no indication of what — meaningless to a user pulling up a links list. And when results loaded, nothing was announced at all, so the screen-reader user sat in silence not knowing the page had updated.
Every one of those passed a visual review and most passed keyboard testing too. They are failures you can only find by listening to what the page actually announces. A screen reader is software that converts the page into speech (or braille) by walking an internal model of the page called the accessibility tree — built from the HTML, the roles, the names, and the states. If your markup builds a poor tree, the screen reader reads a poor page, no matter how good it looks.
You do not need a disability or years of practice to do this testing. You need a screen reader, a handful of keystrokes, and the discipline to close your eyes and judge the page by what you hear.
2 The Rule
A screen reader reads the accessibility tree, not the screen. Looking right is not the same as being announced right — a fake heading, an unlabelled icon, a “Download” link with no context, or a silent update all look fine and read badly. Test by listening, judge the page by what it says out loud, and write the result as steps another tester can re-run.
3 The Analogy
Someone reading the page to you over the phone.
Picture a colleague describing a web page to you down the phone — you cannot see it, you only have their words. A good describer says “heading: your test results; table, four columns; link, download blood-test report PDF; button, book follow-up”. You can build a mental map and act. A poor describer says “some bold text; image; image; link, download; link, download” — and you are lost, because the words carry none of the meaning the layout carried.
The screen reader is that describer, and the words it has to work with come entirely from your markup. A real heading lets it say “heading”; a styled div makes it say “text”. Good alt text lets it name the icon; a missing one makes it say “image”. Screen-reader testing is listening to the describer and asking: from these words alone, could I understand and use this page?
4 How a Screen Reader Reads a Page
You do not need to be an expert user, but you need the mental model and a few core ways of moving. The two screen readers worth knowing for NZ testing are NVDA (free, on Windows, the most common testing tool) and VoiceOver (built into macOS and iOS). They differ in keystrokes but share the same concepts.
A screen-reader user moves through a page in two distinct ways, and you should test both:
- Reading linearly: moving through the content element by element, top to bottom, hearing every piece in order. This tells you whether the reading order and the announcements make sense as a stream.
- Jumping by element type: experienced users rarely read top to bottom. They pull up a list of all the headings to grasp the structure, a list of all the links to find an action, or all the form fields to fill a form. They navigate by landmark (banner, navigation, main, contentinfo) to jump between page regions.
This second mode is the one that catches teams out, because it depends entirely on the page being marked up correctly. If your headings are fake, the headings list is empty. If your links all say “Download”, the links list is a wall of identical entries. If there are no landmarks, there is no way to jump to the main content. A page can read acceptably top-to-bottom and be unusable the way a real user actually navigates it.
5 Semantic HTML Is the Foundation
Almost every screen-reader failure traces back to one root cause: the wrong HTML element, or no element where a semantic one belongs. Semantic HTML — using the element that means what the content is — gives a screen reader the role, the name, and the keyboard behaviour for free. This is WCAG 1.3.1 Info and Relationships: the structure conveyed visually must also be conveyed in the markup.
- Headings (
<h1>–<h6>): a real heading is announced as “heading level 2” and appears in the headings list. A styled div is just text. Heading levels must also nest properly — an<h2>followed by an<h4>with no<h3>tells the screen reader a level is missing. - Lists (
<ul>,<ol>): a real list is announced as “list, 5 items”, giving the user a count up front. A set of divs is read as disconnected lines. - Tables (
<table>with<th>): a real data table lets the user move cell by cell and hear the column and row header with each value — “Result, Cholesterol, 5.2”. A grid of divs reads as a meaningless stream of numbers. - Buttons and links: a
<button>is announced as a button and a<a href>as a link, each with its correct behaviour. The right element tells the user whether something will navigate or act. - Landmarks (
<header>,<nav>,<main>,<footer>): these create the regions a user jumps between. Without them the page is one undifferentiated block.
The pattern is constant: use the native element and the screen reader gets everything; rebuild it from divs and you have to re-supply the role, the name, and the state by hand — and usually miss one.
6 Alt-Text Quality
WCAG 1.1.1 Non-text Content requires every image to have a text alternative that serves the equivalent purpose. The trap is that “has an alt attribute” and “has good alt text” are completely different things — and only the second helps a real user. Judging alt-text quality means asking what the image is for:
- Informative images need alt text that conveys the information. A chart of waiting times needs the key figure or trend, not
alt="chart". - Functional images (an image used as a button or link) need alt text describing the action, not the picture. A magnifying-glass search icon should be
alt="Search", notalt="magnifying glass". - Decorative images that add nothing should have empty
alt=""so the screen reader skips them. A decorative swirl announced as “image, decorative-swirl-2.png” is noise. - Text in images must have that text in the alt. A RealMe logo image needs
alt="RealMe".
The classic failures: alt="image", the filename read aloud (“IMG_4032.jpg”), a missing alt attribute entirely (the screen reader may read the filename), and a meaningful image marked alt="" so it is silently skipped. You catch all of these by listening, not by checking the attribute exists.
7 Accessible Name, Role and Value
WCAG 4.1.2 Name, Role, Value is the criterion that underpins screen-reader testing of any interactive control. For every control, the screen reader needs to announce three things, and you test for all three:
- Name — what is it? The accessible name is the label the screen reader speaks: “Search”, “Email address”, “Book follow-up”. An icon button with no name announces as just “button”. A form field with no associated label announces as “edit” with no clue what to type.
- Role — what kind of thing is it? Button, link, checkbox, text field, tab. The role tells the user how to operate it and what to expect. A div with a click handler has no role and is invisible as a control.
- Value/state — what is its current condition? Checked or unchecked, expanded or collapsed, selected, the text currently entered. A custom toggle that looks “on” but announces no state leaves the user guessing.
The most common screen-reader defect of all is the form field with no programmatic label — a placeholder is not a label, and a label that only sits visually next to the field without being associated in the markup is not announced. Test every input by tabbing to it with the screen reader on and confirming you hear a sensible name, the right role, and (for stateful controls) the current state. If you hear “edit” or “button” with no name, that is a 4.1.2 failure, and usually a 3.3.2 Labels failure too.
8 Live Regions and Writing Reproducible Steps
A sighted user sees a new error message appear, a “saved” toast, or fresh search results loading. A screen-reader user, whose attention is wherever their cursor is, sees none of it — unless the change is announced. A live region (aria-live, or a role like alert or status) tells the screen reader to announce updates to that part of the page as they happen. This is how the silent-results failure from the Hook gets fixed.
What to test: trigger each dynamic change with the screen reader running and confirm it is announced. Submit a form with an error — is the error spoken, or does it appear silently? Add an item to a cart, save a draft, load more results — is each one announced? An update the user is not told about effectively did not happen for them.
Now the deliverable. A screen-reader defect is only useful if a developer can reproduce it, and “the screen reader doesn’t read it right” is not reproducible. Write screen-reader test steps and defects in a fixed shape:
Component: "Download" links on the test-results page
Steps: 1. Turn on the screen reader.
2. Open the test-results page.
3. Pull up the links list (NVDA+F7).
Expected: Each link is distinct, e.g. "Download blood-test report PDF".
Actual: Every link announces only "Download" with no context.
Heard: "Download, link" × 6 — identical, no document name.
Criterion: 2.4.4 Link Purpose (In Context) (A); 2.4.9 (AAA) for out of context.
Severity: High — a user cannot tell the results apart from the links list.
Notice the shape: the exact environment (screen reader and browser, because behaviour varies), reproducible steps including the navigation keystroke, an expected-versus-actual pair, the literal words heard, and the numbered criterion. That is a defect a developer can reproduce and close — the difference between a screen-reader finding that gets fixed and one that gets argued away.
9 Common Mistakes
🚫 Reviewing the page visually and assuming the screen reader hears the same thing
Why it happens: A styled div looks exactly like a heading, so it feels like one.
The fix: The screen reader reads the accessibility tree, not the pixels. A fake heading, an unlabelled icon, and a silent update all look perfect and read badly. Turn the screen reader on and judge the page by what it announces.
🚫 Treating “the image has an alt attribute” as a pass
Why it happens: The attribute is present, so a quick check or scanner is satisfied.
The fix: 1.1.1 needs an equivalent alternative. alt="image" or a filename passes the existence check and fails the user. Read or hear the alt text and ask whether it conveys the image’s purpose; decorative images need empty alt="".
🚫 Testing only by reading top to bottom
Why it happens: Linear reading is the obvious way to use a screen reader.
The fix: Real users navigate by headings, links, and landmarks — they rarely read top to bottom. Pull up the headings list and the links list. A page can read fine linearly and be unnavigable the way users actually move through it (1.3.1, 2.4.4).
🚫 Writing “the screen reader reads it wrong” as the defect
Why it happens: The tester heard the problem but did not capture it precisely.
The fix: Record the environment (screen reader + browser), the exact steps including the navigation keystroke, what you expected, what was actually announced (the literal words), and the criterion. Behaviour varies by tool, so an unspecified defect cannot be reproduced or fixed.
10 Now You Try
Three graded exercises: spot the announcements, fix the alt text, build reproducible test steps. Write your answer, run it for AI feedback, then compare to the model answer.
Below is a description of a Te Whatu Ora appointment-list page as it stands. Identify 3 things a screen reader would handle badly, and for each name the numbered WCAG criterion it breaks.
The page title “Your appointments” is a bold styled
<div>, not a heading. Each appointment row has a status icon (green tick / orange clock) with no alt text. Each row ends with a link that simply reads “View”. When the user cancels an appointment, the row updates and a “Cancelled” message appears, but nothing is announced. The appointment date field for rebooking is a text input whose only label is grey placeholder text reading “dd/mm/yyyy”.
List 3 failures, each with its numbered criterion:
Show model answer
There are at least five real failures; any three correctly named earn full marks. 1. Fake heading (styled div) — Criterion: 1.3.1 Info and Relationships (A). The title is not in the headings list and is announced as plain text, so a user skimming by heading cannot find or structure the page. 2. Status icons with no alt text — Criterion: 1.1.1 Non-text Content (A). The green tick / orange clock carry meaning (confirmed vs pending) but announce as "image" or nothing, so the user loses the status entirely. Note: also touches 1.4.1 if colour is the only differentiator. 3. "View" links with no context — Criterion: 2.4.4 Link Purpose In Context (A). In a links list every entry is "View" with no idea which appointment, so the list is useless for navigation. 4. Silent update on cancel — Criterion: 4.1.3 Status Messages (AA). The "Cancelled" message appears visually but is not in a live region, so a screen-reader user is never told the cancellation succeeded. 5. Placeholder as the only label — Criterion: 3.3.2 Labels or Instructions (A) and 4.1.2 Name, Role, Value (A). The date input announces as "edit" with no persistent name once focused/typed. Strong answers name the number AND name and say what the user hears or misses. The two most-missed here are the silent update (4.1.3) and the link-purpose issue (2.4.4).
Below are four images from a fictional RealMe sign-in and dashboard, each with poor alt text. For each, write the correct alt text (or state it should be empty) and say why, classifying each as informative, functional, decorative, or text-in-image.
A. The RealMe wordmark logo —
alt="logo.png"B. A magnifying-glass icon that is the search button —
alt="magnifying glass"C. A decorative wave graphic at the top of the dashboard —
alt="blue wave decoration"D. A bar chart of this month’s logins, peaking on Monday —
alt="chart"
Give corrected alt text + type + why for each:
Show model answer
A (logo): alt="RealMe" — Type: text-in-image (and functional if it links home). Why: the alt must carry the text shown in the logo; a filename tells the user nothing. B (search icon): alt="Search" — Type: functional. Why: the image IS the button, so the alt must describe the action it performs, not the picture. "Magnifying glass" describes the shape, not what activating it does. C (decoration): alt="" (empty) — Type: decorative. Why: it conveys no information, so it should be hidden from the screen reader with an empty alt. Even "blue wave decoration" is noise the user must sit through; empty alt makes the screen reader skip it. D (chart): alt="Bar chart of logins this month; highest on Monday, tapering through the week" — Type: informative. Why: the alt must convey the information the chart carries — the trend and key figure — not just "chart". If the full data matters, also provide it as an adjacent data table. Strong answers correctly classify each image and explain the rule: informative = convey the information, functional = describe the action, decorative = empty alt, text-in-image = include the text. The most-missed one is C: people write a description instead of using empty alt.
Write a set of 5 reproducible screen-reader test cases for a fictional Waka Kotahi online booking-confirmation page (a heading, a confirmation summary table, a status message after submit, a “Print” icon button, and a “Book another” link). Each case: Environment, Steps (including the navigation keystroke), Expected announcement, and the WCAG criterion. Cover headings, table, status message, icon button, and link purpose.
Show model answer
SR-01 (heading) | Environment: NVDA + Firefox, Windows 11 | Steps: turn on screen reader; open the page; pull up the headings list (NVDA+F7) | Expected announcement: "Booking confirmed" announced as a heading and present in the headings list | Criterion: 1.3.1 Info and Relationships (A) SR-02 (table) | Environment: NVDA + Firefox | Steps: navigate into the confirmation summary table; move cell by cell with the table keys | Expected announcement: each value is read with its row/column header, e.g. "Date, 12 June 2026" | Criterion: 1.3.1 Info and Relationships (A) SR-03 (status message) | Environment: NVDA + Firefox | Steps: submit the booking with focus elsewhere and listen | Expected announcement: the confirmation/status message is announced automatically without moving focus (live region / role=status) | Criterion: 4.1.3 Status Messages (AA) SR-04 (icon button) | Environment: NVDA + Firefox | Steps: Tab to the "Print" icon button | Expected announcement: "Print, button" — a clear accessible name and the button role | Criterion: 4.1.2 Name, Role, Value (A); 1.1.1 for the icon SR-05 (link purpose) | Environment: NVDA + Firefox | Steps: pull up the links list (NVDA+F7 links view) | Expected announcement: "Book another booking" (or similar) — distinct and meaningful out of context, not just "Book another" with no object | Criterion: 2.4.4 Link Purpose In Context (A) A strong set: each case names the environment (screen reader + browser), gives the actual navigation keystroke, states the exact expected announcement, and ties to the right criterion. Weak sets omit the keystroke or the environment, or say "check it reads correctly" with no expected wording.
11 Self-Check
Click each question to reveal the answer.
Q1: A screen reader reads the page from what — and why does that matter?
It reads the accessibility tree, built from the HTML, roles, names, and states — not the pixels on screen. That is why a styled div that looks like a heading, an unlabelled icon, and a silent update all look perfect and read badly. You judge the page by what it announces, not by how it looks.
Q2: Why do you test by pulling up the headings list and the links list, not just reading top to bottom?
Because real screen-reader users navigate by jumping — headings to grasp structure, links to find actions, landmarks to move between regions — far more than they read linearly. A page can read acceptably top to bottom and be unnavigable the way users actually move through it: empty headings list, a wall of identical “Download” links, no landmarks.
Q3: What is the difference between “has an alt attribute” and “passes 1.1.1”?
1.1.1 needs a text alternative that serves the equivalent purpose. alt="image", a filename, or a description of a decorative graphic all have an attribute and all fail the criterion. Informative images convey the information, functional images describe the action, decorative images use empty alt="", and text-in-image includes the text. Existence is not quality.
Q4: What are the three things a screen reader must announce for every interactive control?
Name (what it is — “Search”, “Email address”), role (what kind — button, link, checkbox), and value or state (its current condition — checked, expanded, the text entered). This is WCAG 4.1.2. Hearing “button” or “edit” with no name is the failure.
Q5: What must a reproducible screen-reader defect record?
The environment (which screen reader and browser, since behaviour varies), the exact steps including the navigation keystroke used, the expected announcement, what was actually announced (the literal words heard), and the numbered WCAG criterion. “The screen reader reads it wrong” cannot be reproduced or fixed.
12 Interview Prep
Real questions asked in NZ QA interviews for roles on accessible public-facing systems. Read the model answers, then practise your own version.
“The page passed visual review and keyboard testing. Why would you still run a screen reader over it?”
Because a class of failures only shows up in what the page announces. A heading styled from a div looks and tabs fine but is invisible to the headings shortcut screen-reader users navigate by. An icon button can be reachable by keyboard yet announce as just “button” with no name. A result that loads updates the screen but is never spoken, so the user sits in silence. None of those are visible to the eye or catchable by the keyboard — the screen reader reads the accessibility tree, and the only way to test the tree is to listen to it.
“How do you judge whether an image’s alt text is good?”
I classify the image first. If it is decorative it should have empty alt so the screen reader skips it. If it is functional — an icon that is a button — the alt describes the action, like “Search”, not the picture. If it is informative, the alt conveys the information, like the trend in a chart, not just “chart”. If it contains text, like a RealMe logo, the alt includes that text. The test I use is to cover the image and ask what the text would need to tell me if the picture were gone. And crucially I judge it by listening — alt="image" or a filename has an attribute and still fails 1.1.1.
“A developer can’t reproduce your screen-reader defect. How do you write it so they can?”
I give them five things: the environment — which screen reader and browser, because announcements differ between NVDA and VoiceOver; the exact steps including the navigation keystroke, like pulling up the links list; what I expected to hear; what was actually announced, in the literal words; and the numbered WCAG criterion. So instead of “the links don’t read right”, it’s “in NVDA with Firefox, open the links list, expected distinct link names, heard ‘Download’ six times — 2.4.4 Link Purpose.” That is something they can sit down, reproduce, and close.