Skip to content
easeweb
Search topics

Charts whose numbers a screen reader can't read

A bar chart is drawn on a canvas with no text in it, or named only "Orders chart", so a screen reader skips it or reads the name and never a number.

WCAG 2.2
SC 1.1.1A
Required by
Section 508 · EN 301 549 (EU)
Broken <canvas id="orders"></canvas>
The accessibility problem illustrated: No vision:Which day was busiest?
01

The problem

Screen reader users can't learn what a chart shows: not its finding, and not one of its numbers.

02

Try it

Cover the chart, then find the busiest day from what is read out.

  • Broken 1: the panel shows what a screen reader reads, from the top of the card. Does any of it come from the chart?

  • Broken 2: the chart now has a name. Does the name tell you which day was busiest?

  • Apply a fix. With the data in the name, every count is read with the chart. With the table, also open “Show the numbers” and read the rows, with the chart covered or not.

Broken Can you fix this?

Orders per day

Last week

Reading the card from the top, a screen reader says:

  1. Orders per day, heading
  2. Last week

A recreated demo. The broken version is intentionally inaccessible.

03

The fix

Say what the chart shows, and give its numbers as text.

Before

A chart drawn on a canvas with nothing to read

<section class="card">  <h2>Orders per day</h2>  <p class="range">Last week</p>  <canvas id="orders"></canvas></section>
What is wrong2 points
  • The bars, the day labels and the axis are painted as pixels, so none of them can be read.
  • The canvas has no name and nothing inside it, so a screen reader passes it without a word.
After

Write the data into the chart's name

<section class="card">  <h2>Orders per day</h2>  <p class="range">Last week</p>  <canvas id="orders" role="img"></canvas></section>
How it is fixed3 steps
  1. Give the canvas role="img", so it is read as one image with a name. A canvas has no role of its own that takes a name.
  2. Build the name from the same two arrays the chart is drawn from: what the chart shows, its main finding, then every day with its count. A screen reader now says "Orders per day, last week. Busiest on Saturday, with 31. Monday 12, Tuesday 15, …, Sunday 20, image".
  3. Set the name in the code that draws the chart, so a new week's data gives a new name.

This fixes both Befores and passes 1.1.1 for a chart this small: seven values fit in a sentence a listener can follow. The numbers reach only screen reader users, though, and as one string, which can't be paused on Thursday or read again from Friday. A chart with dozens of points, or several series, needs the table in the next fix.

04

Design ideas

A chart can carry its numbers in words.

Four ways to draw last week’s orders with the numbers there as text, and one dashboard tile that gives only a line. Try the Chart and Table switch.

In the design file

  • Write the chart’s title as what it shows, such as “Saturday was the busiest day”, with what is counted under it.
  • Put every number the chart shows where it can be read as text, on the bars, in a table view or both.
  • Write the sentence a screen reader should hear for the chart, with what it shows, the main finding and where the numbers are.
  • Mark which words and figures come from the data, so they are built from the same numbers as the bars.

Passes

  • Orders per day, last week

    • Monday 12
    • Tuesday 15
    • Wednesday 14
    • Thursday 18
    • Friday 24
    • Saturday 31
    • Sunday 20
    Counts written on the bars Each bar runs along its day and ends in its count, set as real text in #1f2933, 14.76:1 on white. A screen reader reads the list as “Monday 12”, and nobody has to follow a bar across to a gridline.
  • Saturday was the busiest day

    Orders per day, last week

    The finding as the title “Saturday was the busiest day” says, in words everyone reads before the bars, what the chart is there to show, with “Orders per day, last week” in #6b7280 grey, 4.83:1, under it. Write the title from the data, so it changes with the week.
  • A Chart and Table switch Two buttons above the plot swap the bars for a table of the same counts, which anyone can read, zoom or copy. Draw the table view with as much care as the chart, and the switch with its chosen side filled.
  • Orders last week 134 Up 18% on the week before
    The figure first, the line after A dashboard tile leads with its figure, “134”, and “Up 18% on the week before” in #1f6b3a green, 6.52:1, with an arrow, and the sparkline under them only repeats that in a shape. The line can then be hidden from a screen reader, since the words already say it.

Fails

  • Orders
    A sparkline with no figureWCAG 1.1.1 The tile holds “Orders” and a line, and nothing else, so the design gives no words or figure for what the line shows. The rise reaches only people who can see it, unless a developer makes up the words. Write the figure and the change on the tile.
05

Verify the fix

5 checks, no mouse.

Test with: Screen reader, Zoom

0 of 5 checked

Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat whenever the chart component or its data source changes.

Limits

This is a starting pattern, not a guarantee for every chart. Chart is Chart.js, and the same text alternative applies to a chart drawn by any library or by hand. This guide covers a chart's text alternative. A chart whose points, legend or tooltips do something only for a pointer, such as a value shown only on hover or a bar that filters the page when clicked, is a different failure: a legend is covered in chart legends a keyboard can't toggle, and a value shown only on hover in chart tooltips a keyboard can't open. For an image that isn't a chart, see images that tell something but have no alt text. Test the complete dashboard with your target assistive technology.

This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.

EaseWeb service

Fixed it? Keep it from coming back.

I turn guides like this one into rules your coding agents follow and checks your CI runs. Then I retest by hand with a keyboard and screen readers, periodically.

See the service