
Tags:
I've written before about how to make accessible graphs and charts, but one type of chart I didn't touch upon was a flowchart, which is different enough that it really warrants a bit more detail explaining how to best make it as accessible as possible.
Contents
Main Accessiblity Issues with Flowcharts
My typical approach to charts that are accessible and still retain the visual characteristics that make them what they are is to use SVGs. The SVG format is good for this, as it's just markup that can accept all the usual aria-*
and role
attributes to help the web browser understand your intent behind the image. They can also be very easily styled with CSS, which makes it a much more simple task to generate dark mode or high contrast variants.
So, what are the main problems that you can encounter when creating your flowcharts?
- Poor colour contrast with the flowchart elements and their text.
- No support for a screen reader.
- No keyboard support.
- Difficulty for people with cognitive issues to follow the flow of more complex charts.
So, how can we create something that can retain the look of a flowchart, whilst being more accessible?
The Initial Concept
My first thoughts on this would be to have the key elements of the SVG use specific role
values so that they would appear as list items in the browsers accessibility tree. I had also considered using nested lists to show the links between choices through the hierarchy, but that wouldn't work quite so well for more complex flow charts.
Consider this humorous problem solving flowchart often shared about by developers:

There will be several parts to making this an accessible SVG.
Identifying and Grouping Question and Statement Blocks
First, I wanted to create a group around each question/statement and make them named anchors by giving each one a uniqueid
. Each shape block, with corresponding text, looked something like this:
<path d="shape path..."/>
<text x="271.550781" y="37.59375">Does</text>
<text x="262.449219" y="53.59375">it work?</text>
Then, I wrapped it within a <g>
element with an id
, and repeated for each block throughout the SVG. I also gave each one a corresponding class of question
or statement
in order to style them all more easily with CSS:
<g id="does-it-work" class="question">
<path d="shape path..."/>
<text x="271.550781" y="37.59375">Does</text>
<text x="262.449219" y="53.59375">it work?</text>
</g>
Making a List
Now that the SVG had some more clarity and structure, I wanted to turn the whole thing into a list, at least as far as the accessibility tree in the browser was concerned. For each group created in the previous step, I added a role="listitem"
, then grouped the whole lot inside yet another <g>
with a role
of list
:
<g id="questions-statements" role="list">
<g id="does-it-work" class="question" role="listitem">
...
</g>
<g id="dont-mess-with-it" class="statement" role="listitem">
...
</g>
<g id="did-you-mess-with-it" class="statement" role="listitem">
...
</g>
...
</g>
Ignoring Empty Elements
One problem that browsers can sometimes have, is to present empty elements in unusual ways. I remember Safari having quite an odd bug when an SVG was embedded using an <object>
tag, trapping the screen reader and keyboard on seemingly nothing for as long as the SVG was complex. In order to prevent that from happening, any elements that were not key to the accessibility of the flowchart would have an aria-hidden="true"
added to prevent the browser from ever surfacing them to the accessibility tree.
While I was doing this, I wanted to also consolidate the multiple <text>
elements into a single label that could be presented to the user. In the end, I settled for this approach:
<g id="does-it-work" class="question" role="listitem">
<title>Does it work?</title>
<g aria-hidden="true">
<path d="..."/>
<text x="..." y="...">Does</text>
<text x="..." y="...">it work?</text>
</g>
</g>
The <title>
element serves two purposes in SVGs. First, it supplies a text name that can be presented in the accessibility tree, and second, it also shows as a tooltip (in supporting browsers) much like the similar title
attribute behaves in HTML.
Making the Options Links
The next step was to make the SVG somewhat interactive, by converting the text labels on the flowchart arrow lines into links that could be used by keyboards or pointing devices. This was achieved in two parts: I made each label an <a>
element (these behave exactly the same as they do in HTML) pointing to the id
of the corresponding block they should point to, and then I moved those links up into a new group along with each question/statement block.
<g id="does-it-work" class="question" role="listitem">
...
<g class="paths">
<a href="#did-you-mess-with-it">
<text x="..." y="...">No</text>
</a>
<a href="#dont-mess-with-it">
<text x="..." y="...">Yes</text>
</a>
</g>
</g>
Giving Links Unique Contextual Text
Now, it should be obvious that by doing what I described in the previous step, there will be a lot of links that have the exact same text, but that all point to different anchor points in the SVG document. One of the first rules about links in web pages is ensuring that they have unique and appropriate text content to allow better navigation by people using screen readers.
Thankfully, this is easily fixed without needed to change the visual labels, which already have enough context within the layout of a flowchart. The answer is fairly simple, add appropriate aria-label
properties to each of the links with some better content:
<a href="#did-you-mess-with-it"
aria-label="No, it does not work"
aria-describedby="does-it-work"
>
<text aria-hidden="true">No</text>
</a>
<a href="#dont-mess-with-it"
aria-label="Yes, it works"
aria-describedby="does-it-work"
>
<text aria-hidden="true">Yes</text>
</a>
I've made a few changes here:
- Each link now has an
aria-label
with a more contextual bit of text that describes the purpose of the link. - Each link also now has an
aria-describedby
attribute pointing to the parent element byid
to give it some further context to what it belongs to. This might be overkill, but I thought I would add it anyway as most screen readers don't announce descriptions by default, only when requested to. - Lastly, I hid the original text label (the visual one) from the a11y tree, as having both would be confusing.
Hiding the Arrows
The very last thing to do was hide the arrows from the screen reader just in-case we encounter a weird bug with a particular browser/reader combination that someone might be using. To do that, I created one final group (<g>
) around the lines and arrows, and added an aria-hidden="true"
to it.
The End Result
This is the end result. Visually, it's the same chart, but under the hood, it should now work much more nicely with whatever browser and screen reader anyone might be using:
Comments