Command Palette

Search for a command to run...

Hectal
PHASE 15Advanced ~24 min· topic 1 of 7

Topic 15.1

What a Screen Reader Hears

In one line

A screen reader does not look at your chart. It reads the accessibility tree the browser builds from the page, so an SVG with no name is "image" at best, and a canvas with nothing added is silent.

Think of it like this

A museum where a guide reads every label aloud to a visitor who cannot see. A painting with a card that says "Harbour at dawn, 1891: fishing boats leaving a calm bay" is easy to enjoy. A painting with no card is "a painting". A painting with a card that says only "Painting" is not better. The picture is the same, and the card is all the visitor gets.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

screen reader
A program that speaks the page aloud (or shows it in braille) for a person who cannot see the screen.
accessibility tree
A second tree the browser builds from the page. Screen readers read it instead of the pixels.
role
What a node is, in the accessibility tree: image, button, table, slider.
accessible name
The short label a node has in the tree, taken from aria-labelledby, aria-label or a title child.
accessible description
A longer sentence joined to a node with aria-describedby, spoken after the name.
aria-label
An attribute that gives an element an accessible name in plain text.
assistive technology
Any tool that helps a person use the web in another way: screen readers, switch devices, voice control.
fallback content
Text between the <canvas> tags, shown by software that does not draw the canvas.

Step by step

01Start with the page, not the picture

You see bars. The browser sees a tree of elements. Before a screen reader speaks, the browser turns that tree into the accessibility tree and drops everything that has no meaning for it.

Start with the page, not the picturediagram
Rendering diagram…

02Look at the same seven bars three times

The first example draws one week of rides three times: bare, with role="img" only, and with a role and a name. A small function finds each chart's name the way the browser does.

Bare and role-only both end with an empty name. Only the third has words to speak. The seven bars are identical in all three, which is the point: the picture never changed, only what the page offers a reader.

03Meet the canvas

The second example draws five bars on a canvas four times: with nothing, with fallback text, with a role and a label, and with aria-hidden. The canvas has no children in every case, because it is one bitmap. Only text you add can speak for it.

04See the tree the browser really built

The first code block after the examples is a measurement, not a live example: a Playwright script asked Chromium for the accessibility tree of each case. The roles it prints (image with a name, image with no name, nothing for a bare canvas) are what screen readers start from.

05Try the widget

The widget shows the same Lumen chart in three versions and the words each one hands to a screen reader. Use its "Hear it" button to get a feel for speech. A real screen reader says it in its own voice and order.

Try it yourself

  1. 1

    Use a title child instead of aria-label

    In the first example, build the third chart's name with a <title> element: const t = document.createElementNS(NS, "title"); t.textContent = "Rides per day, 2 to 8 June 2025. Monday was quietest with 2,979 rides, Tuesday busiest with 3,992."; svg.prepend(t); instead of the aria-label line. The Console prints the same three lines as before: the name is found in the <title>. Chromium's tree gave the same image name for both (see the measured block).

  2. 2

    Give the canvas an empty label

    In the second example, change the role + aria-label canvas's label to an empty string: c.setAttribute("aria-label", ""). The Console now says offered: nothing for that line, as for the canvas with nothing. A label that exists but is empty gives a reader nothing.

Code & diagrams

Try it: interactive

What the page hands to a screen reader

Switch between the bare, labelled and full versions. For each, read what the role and name are, and decide whether Meera could answer "which day was quietest?".

The same chart, three ways New tab

The function accessibleName follows the browser's order: aria-labelledby, aria-label, then a title child. In your own work, never write this yourself: set the attribute and let the browser compute the name.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

bare      | role: (none) | name: (empty)
role only | role: img    | name: (empty)
labelled  | role: img    | name: "Rides per day, 2 to 8 June 2025. M..."
Bars in every version: 7, 7, 7
A canvas: what can you give it? New tab

"Offered" is the name or text a person's tool would receive. The last line proves the bars exist as pixels: eyes get them, a screen reader gets only your words.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

nothing added      | children: 0 | offered: nothing
fallback text      | children: 0 | offered: "Rides, Monday to Friday: 2,979 to 3,992."
role + aria-label  | children: 0 | offered: "Rides, Monday to Friday: 2,979 to 3,992."
aria-hidden        | children: 0 | offered: nothing (hidden from assistive technology)
Pixel inside the first bar: 31,122,111,255
The accessibility tree Chromium built (measured, not live)text

Measured with a Playwright 1.63 script in its Chromium (CDP Accessibility.getFullAXTree and ariaSnapshot). The roles are Chromium's names (it says "image"). NVDA, VoiceOver and TalkBack announce these in their own words.

bare svg                   -> SvgRoot, then the text "Mon" and "Tue" as loose text
svg role=img, no name      -> image (no name), then the text "Mon Tue"
svg role=img + aria-label  -> image "Rides on Monday and Tuesday"
svg role=img + <title>     -> image "Rides on Monday and Tuesday"
svg + aria-label, no role  -> image "Rides per day"   (Chromium only: do not rely on it)
svg role=img aria-label="" -> image (no name)
svg role=img aria-hidden   -> nothing
canvas, nothing added      -> nothing
canvas role=img + label    -> image "Rides on Monday and Tuesday"
canvas with fallback text  -> the fallback text "Rides: Monday 2,979, Tuesday 3,992."
svg role=img with a focusable <g> inside -> image "Rides per day", and the <g> as a separate group

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Hide the chart from assistive technology

In the second example, add c.setAttribute("aria-hidden", "true"); inside the role + aria-label canvas's setup, after its label.

terminal
$ Console
── what you'll see ──
role + aria-label | children: 0 | offered: nothing (hidden from assistive technology)

Myth vs fact

Myth

A chart is a picture, so a screen reader cannot do anything with it.

Fact

A screen reader can read exactly what you offer: a name, a description, a table and a keyboard path. The picture is only one way to show the answer.

Myth

Adding aria-label="chart" makes it accessible.

Fact

It gives the node a name and no information. A name should say what the chart shows and, when possible, the finding.

Myth

Canvas is accessible because the browser can see it.

Fact

The browser draws pixels and builds no tree for them. A canvas with nothing added is invisible to a screen reader.

Myth

If the automated test passes, a screen reader user is fine.

Fact

Tools check that a name exists, not that it is true or useful (Topic 15.6 measures this).

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Children of role="img" are presentational in the ARIA spec, so anything focusable inside it is unreliable: Chromium exposed a focusable <g> inside an img as a separate group, and other tools may not. When a chart needs reachable parts (Topic 15.4), use role="group" for the chart and give each part its own role and name.

  • ▸

    aria-label is not translated by some browser tools the way visible text is, and it is invisible to sighted users. Visible text is better when it can be: Topic 15.2 prefers a visible description joined with aria-describedby.

  • ▸

    Name and description are separate on purpose: the name is spoken whenever the node is reached, the description is offered after it and some tools let a person skip it. Keep the name short.

Remember this

  1. 1

    The problem this solves: a chart is made of shapes, and shapes have no meaning to software. Without a name, a person using a screen reader hears "image" or nothing, and cannot tell a year of rides from a logo. A name, a role and a description turn the picture into an answer.

  2. 2

    A screen reader reads the accessibility tree, not the screen. The browser builds a second tree next to the page's DOM, called the accessibility tree. Each node has a role (what it is: button, image, table), a name (what it is called), sometimes a description (more detail) and a value or state. The screen reader, and any other assistive tool, reads that tree. A <rect> with a fill of teal is only paint: it is not in the tree as a bar.

  3. 3

    What a bare SVG gives. An <svg> with no role and no name gives a screen reader almost nothing to announce: Chromium builds a node for the SVG root and then the loose <text> labels ("Mon Tue") as plain text. The seven bars are not in it. What a screen reader says for that depends on the product and its settings, so describe it generally: at best a nameless "graphic" or "image", often just the axis labels read in a row, with no numbers and no finding.

  4. 4

    **role="img" plus a name is the first fix.** role="img" says "treat this whole chart as one image", and the accessible name says what it shows. The browser takes the name from aria-labelledby first, then aria-label, then a <title> child. Chromium also exposes a named SVG as an image without the role, but role="img" makes the intent explicit in every browser. The name is one or two sentences with the finding, not the word "chart".

  5. 5

    Canvas is a bitmap with nothing inside. A <canvas> holds pixels, and pixels have no meaning. With nothing added, Chromium makes no node for it at all: a screen reader user does not even learn it exists. Give it role="img" and an aria-label, or put fallback text inside the <canvas> tags. A name is still not a chart: the longer description, the table and the keyboard path come next (Topics 15.2 to 15.4).

  6. 6

    Hidden means hidden. aria-hidden="true" on a chart removes it from the tree on purpose, and a screen reader then skips it entirely. Use it only for pure decoration, such as an icon next to a word that already says the same thing. An empty aria-label="" does not give a name: the image stays nameless. These two mistakes look like accessibility work in the source, and they change nothing for the reader.

  7. 7

    Test with the real tool, and know why you do. The tree shows what the page offers, but only a screen reader shows what a person hears, because speech, verbosity and the order of reading differ by product. NVDA is free on Windows, VoiceOver is built into macOS and iOS, and TalkBack is built into Android. Learn a few keys (move by headings, move by tables, move by graphics) and read the vendor's own guide. This is WCAG 1.1.1 Non-text Content (level A) and 4.1.2 Name, Role, Value (level A) in practice.

Explain it without notes

01

What is the accessibility tree and why does a screen reader read it instead of the page?

02

What does a screen reader get from an SVG with no role and no name? From a canvas with nothing added?

03

Where does the browser take an accessible name from, in order?

04

Why is aria-label="chart" almost as bad as no label?

05

Why does a team still need to test with a real screen reader after reading the tree?

Practice

01

Write the HTML for an SVG of the stations chart that gives it a role and a name with the finding "Lantern was the busiest station in July with 7,260 rides".

02

A teammate adds aria-hidden="true" to the rides line "because it already has a table". Say what a screen reader user now gets and what to change.

Trade-offs

  • ↔

    A short name is quick to hear and cannot hold the finding and the shape. Put the finding in the name, and the detail in a description that a person can skip.

  • ↔

    Testing with a real screen reader takes time and a learning curve. The tree check is fast and repeatable, but it cannot tell you how a sentence sounds.

Done when you can

  • I can say what the accessibility tree is and what a screen reader reads from it.

  • I can give an SVG a role and a name, and a canvas a role and a label.

  • I can say what a bare SVG and a bare canvas hand to a screen reader.

  • I know that aria-hidden and an empty aria-label take the chart away.

  • I know which WCAG criteria this is: 1.1.1 and 4.1.2.