Accessible SVG line graphs

SVG is often used for data visualisation, but because SVG lacks the semantics to express structures like bar charts, line graphs, and scatter plots, the content is difficult for screen reader users to interpret. The solution is to use the technique for creating accessible SVG tables as your starting point.

Let’s take a simple SVG line graph as a working example. In this graph the y axis represents usage by percent, and the x axis represents time. The three lines represent the different screen readers:

  • Jaws is a solid blue line;
  • NVDA is a dotted black line;
  • VoiceOver is a smaller dotted green line.

Using the graph you can tell what percent of usage each screen reader had at a particular point in time. For example, in January 2014 74% of screen reader users used Jaws, in May 2012 43% used NVDA, and in July 2014 30.9% used Voiceover.

This data can be represented as a table: where the rows represent the screen readers, the columns represent the points in time, with the usage percentage data in the table cells.

It’s a good idea to give people choices about the way they consume content, so letting people choose between a graphical and tabular view of the data would be a good thing to do in any case. But in the interests of making your primary content as accessible as it can be, you can use the following ARIA to add table semantics directly in the SVG:

Adding ARIA

Use a g element with role="table" to represent the table:

<g role="table">...</g>

Add role="row" to each of the g elements that represent the table rows:

<g role="row">...</g>

Add role="columnheader" to each of the text elements that represent the column headers:

<g role="row" class="grey small">
<text role="columnheader" x="334.5" text-anchor="middle" class="grey" y="306">Time</text>
<text role="columnheader" x="130" text-anchor="middle" y="269">Jan 2009</text>
<text role="columnheader" x="232" text-anchor="middle" y="269">Dec 2010</text>
<text role="columnheader" x="334.5" text-anchor="middle" y="269">May 2012</text>
<text role="columnheader" x="436.5" text-anchor="middle" y="269">Jan 2014</text>
<text role="columnheader" x="539" text-anchor="middle" y="269">Jul 2015</text>
</g>

Use a g element with role="rowheader" to represent the header for each row in the table. Move the title element that is the first child of the rowheader, so it is the child of the path element, and give the path element role="img".

<g role="row">
<g role="rowheader">
<path role="img" transform="translate(79,63)" d="M 51 48.5 C 51 48.5 112.5 53 153.3 56.8 C 194 61 214 68 255.5 68 C 296 68 317 67.5 357.7 67.5 C 398.5 67.5 460 105 460 105" class="s1" stroke-linecap="round">
<title>Jaws</title>
</path>
</g>
...
</g>

It’s necessary to move the title element inside the path element, and to give the path element role=”img” in order to fool browsers into thinking there is content inside the left-most column of the table. IE doesn’t need this, but it’s a workaround for other browsers.

Use a g element with role="cell", to represent each of the table cells. Add role="img" to each of the use elements that represent the content of the cells:

<g role="cell">
<use role="img" href="#points-0" x="130" y="112">
<title>74%</title>
</use>
</g>

The img role is again used to expose the content as a graphic in the browser, with the title element providing its accessible name.

Use the aria-hidden attribute to hide the y axis values, the y axis label (“Percentage usage”), and the legend, from screen readers. The same information is available to screen reader users through the row and column headers, so this avoids duplication of information without removing it from the visual presentation.

A working demo of the chart has all of these changes applied.

The state of SVG accessibility support in browsers and screen readers is still highly inconsistent, even when ARIA is used to polyfill semantic information. This solution works with Jaws in Chrome and IE, but only partially in Firefox (because Jaws doesn’t recognise the contents of the table cells in that browser); NVDA struggles with the ARIA table semantics in Chrome, Firefox, and IE; whilst this solution works well with VoiceOver in Safari.

The upshot is that this technique is enough to make the primary SVG content more screen reader accessible, and support is likely to improve as browsers and screen readers improve their support for SVG and ARIA, but it isn’t enough to make it completely so. For this (and many other good reasons), it’s a good idea to provide an alternative view of the information, for example by providing both a graphical and a tabular view of the content (as noted above).

Thanks to WebAIM for the data (taken from their screen reader surveys) used to create this line graph, and to Chaals McCathie Nevile who borrowed the original SVG chart from HighChart and started thinking about its accessibility.

3 comments on “Accessible SVG line graphs”

Skip to Post a comment
  1. Comment by Craig Francis

    Thanks for the article Léonie, after all these years I had no idea you could have more than one element in an SVG.

    Out of interest, if you have a simple bar graph, where it’s a set of things, and each one has a single value (shown on the page above each bar), does it make sense to turn that into a table, or simply have it being read out as “Item A: 5”, “Item B: 12”?

    Also, your original.html, there is a couple of minor typos – on line 152 there is a comma instead of a less than sign (,/use>), and on line 159 there is a extra double quote ()

    1. Comment by Léonie Watson

      Thanks Craig. Fixed those typos!

      If the data really is that simple, then a list could be used to represent it semantically. It would still need a short description to explain the incremental values of the Y axis though (assuming it is a vertical bar chart).

  2. Comment by Craig Francis

    Good point on using a list, that would be much better than text being read out without any structure.

    As to the short description, should that be in the SVG, if a description already exists just above the graph? I wanted it to be available to everyone.

    I’m hesitant to duplicate it within the SVG as well… but at the same time, if someone is viewing the page with a screen reader, might they jump to the SVG and not know what it is (then again, this is an inline SVG, so it’s not really seen as a single image)… maybe an argument for aria-labelledby or aria-describedby?

    Ref: https://css-tricks.com/accessible-svgs/

Comment on this post

Will not be published
Optional