Case Study: Implementing Accessible Data Charts for the Khan Academy 2018 Annual Report

A few months ago I teamed up with SuperFriendly to create an accessible micro-site for the Khan Academy 2018 Annual Report. The site is a very beautiful visual representation of Khan’s real-life impact on world education, their end-of-year financial reports, and more. By nature, the annual report contains a lot of data and visualizations and charts to represent it. My mission was to make sure that the way this data is presented and implemented is as accessible to site’s visitors as possible, regardless of how they explore the site.

Data visualizations are a great way to make information stand out and sometimes a lot easier to parse and understand. But they also come with their own accessibility challenges that you need to be aware of.

An example of a chart from the Khan Academy 2018 Annual Report. Screenshot.
The Khan Academy annual report represented all of the main data showcasing the impact they had on world education using different kinds of charts — simple and complex.

When it comes to visualizing data on the Web, SVG is the most used format. It is perfect for creating data visualizations because it comes with all the elements needed to create the shapes used to represent information. Because SVG is an XML format, similar to HTML, it comes with a lot of tags to represent different kinds of elements, mostly shapes. We have elements for creating basic shapes such as circle s, ellipse s, rect angles, polygon s, polyline s, line s, and more complex path s, all of which are used to draw all kinds of data charts and visualizations.

And often times, these charts and visualizations are also animated and interactive; and SVG provides us with the ability to animate and interact with the images we create with it — using CSS and JavaScript.

But SVG data visualizations are, at the end of the day, SVG images. This means that when a screen reader comes across one, it is likely going to announce it the same way it would announce any image: as an image, with an accessible name (because I’m assuming that the image does have an accessible name provided in the alt attribute). This, in turn, means that the screen reader is not going to announce the content presented inside the chart to the user by default. It is only going to announce whatever accessible name we provide it with. Making sure it announces the content inside the image is something that requires a little more work on our side.

How accessible are SVG data visualizations & charts?

Albeit being a perfect candidate for visually representing information, SVG is not equipped with the semantics needed to convey the content of that information to the user.

In her article about creating accessible line graphs with SVG, Léonie Watson says:

“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.”

Léonie wrote a few articles about making content inside SVG accessible that I will link to at the bottom of this article. The concept in all of them is the same: use some of the available ARIA roles to modify the semantics of SVG elements to be announced to screen readers as something other than what they are.

SVG has no native semantics for representing structures like tables, but ARIA1.1 introduces a number of roles that can be used to polyfill the necessary semantic information. — Léonie Watson, Accessible SVG Tables

For example, in her article, she uses the ARIA table attributes to announce a visual line graph as a table to screen reader users, which makes it possible for them to announce the data inside those tables to their users as well. This is possible because a table is often times an appropriate alternative way to represent the information in a line graph.

But Léonie finally notes (and emphasis is mine here) that:

“The state of SVG accessibility support in browsers and screen readers is still highly inconsistent, even when ARIA is used to polyfill semantic information.

The upshot is that this technique is enough to make the primary SVG content more screen reader accessible […] 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”

Personally, I’d avoid hacking my way around making an SVG chart accessible using ARIA roles. Most of the charts in the Khan Academy annual report were more complex, so using ARIA roles to change their semantics would not only prove to be counter-productive, but also risky, especially given how inconsistent screen reader and browser support is, and how important those charts are for the site’s visitors.

So, I chose the alternative view of the information route. And with all the different SVG embedding techniques available to use, SVG makes all kinds of fallbacks easy to implement.

Choosing the most appropriate SVG embedding technique

There are 6 ways to embed an SVG on a Web page. Choosing the most appropriate one highly depends on your requirements and what you need the SVG to be capable of and the kind of fallback that you need.

<iframe> , <object> and inline <svg> all tick all of the above boxes.

I’m not a big fan of <iframe> s, and <object> already gives me everything I need that <iframe> does, so, out of these two, I always choose <object> .

In addition to the above requirements, I had a couple of other considerations in mind:

If I were to embed the charts inline, they would “pollute” my HTML, and would not be cached unless the whole page is. That’s not ideal. Whereas an <object> would reference an external SVG image which, after the first request, would then be cached, making subsequent visits faster.

Also, on a more design-related note: I was working with SVG images exported from Adobe Illustrator, which tends to repeatedly create and use the same IDs and CSS class names for the images it exports. If I were to embed all of the images inline, the IDs and class names would clash and I would need to spend time I didn’t have to go over each SVG and provide it with unique class names to avoid the style inheritance nightmare, because, by default:

Styles within an inline <svg> are not scoped to it.

This means that if you have two inline svg s on the page, the styles from the second SVG in the DOM order will override the styles in the first one for elements with shared class names.

And last but not least, I love the clean and uncluttered way that <object> enables me to provide text fallback for my SVG images: simply place the text fallback in between the opening and closing object tags, and that text will be displayed wherever SVG is not supported and/or whenever the SVG fails to load.

So, <object> it is.

Embedding the charts

The initial base code for one of the simple charts would then look like this:


type="image/svg+xml" data="/images/long_beach.svg">

<p>Khan Academy math usage for 30 minutes per week proved to
improve more than 5,000 Long Beach students scores by 2 times
in the Smarter Balanced Assessment.</p>


This was just the base markup, but I was curious enough to check how it would be announced by a screen reader. I’m on macOS so I usually test my work with VoiceOver (VO) on Safari.

VO announced the chart as a frame, and used the file name of the SVG (in this case long_beach.svg ) as the accessible name for it. Ouch.

I was expecting the random name situation since my markup doesn’t yet include a label for the image, but I didn’t know how an object is usually announced. I was also curious if VO would somehow recognize or find the fallback text and announce it. It didn’t. Now, it was time to start “fixing” the situation.

I want my chart to be announced as an image to start, so I needed to modify its semantics using ARIA role . To give it an accessible name, I used aria-label :

aria-label=“Khan Academy Math usage level in Long Beach. Chart."

type="image/svg+xml" data="/images/long_beach.svg">

<p>Khan Academy math usage for 30 minutes per week proved to
improve more than 5,000 Long Beach students scores by 2 times
in the Smarter Balanced Assessment.</p>


With these two attributes added, VO communicated my chart as an image, and used the label I gave it as its accessible name. Great.

But a visitor using VO would now know that there is a chart showing Math usage levels in Long Beach, but they would not be able to access the data inside that chart.

Since I already have a text fallback clearly describing the data in the chart right there in my markup, I thought I could use that instead of try to communicate the same content in a second way. That text fallback was not being exposed to my screen reader. In other words, it was hidden from screen readers.

But I already know that I can expose hidden content to my screen reader to announce if I reference that content inside of aria-labelledby . I’ve used this in my previous article to provide a visually-hidden accessible label to an icon-only button. So it makes sense that I’d be able to do the same using aria-describedby .

There are several reasons why I’d want the image’s text content exposed using aria-describedby not aria-labelledby :

There is a major difference between the way the content referenced in aria-labelledby is announced versus that referenced in aria-describedby. The accessible name is announced before the image’s role is announced (in VO, at least); the description is announced after the image’s role, with a short pause preceding it.

That’s exactly how I want my text to be announced. So, with all that taken into account, the final code for my chart looks like this:

< object
aria-label=“Khan Academy Math usage level in Long Beach. Chart."

type="image/svg+xml" data="/images/long_beach.svg">

<p id="long_beach_desc">Khan Academy math usage for 30 minutes per week proved to
improve more than 5,000 Long Beach students scores by 2 times
in the Smarter Balanced Assessment.</p>

< /object>

This works very well, including for images that have longer descriptions. Of course, we made sure (thanks, Jessi) that the descriptions were as concise and succinct as possible, so the user is not overwhelmed with long announcements but would still get a very clear and accurate text version of the information provided in each chart.

“Can’t you just use <figure> for the charts?”

I got this question a couple of times after speaking about my implementation choice above — once during a workshop, and once after a talk.

I’m guessing that the idea here is that you would implement the SVG chart in an img inside a figure and use the figure ’s figcaption to provide the text alternative of the chart’s content to screen reader users. I assume the suggestion would be to hide the figcaption in this case visually (because we don’t show it visually, of course) and make it available to screen readers only, using a utility class such as sr-only .

< !-- This is what you should NOT do.--> 
< figure>

<img src="/path/to/chart.svg" alt="ACCESSIBLE_CHART_TITLE" />

<figcaption class="sr-only">
<p>Here goes the text that describes the information inside the chart.</p>
<p>Note that this text could be a couple of a few paragprahs long.</p>
<p>It might even be appropriate to represent the data using a table!</p>

< /figure>
* Utility class to hide content visually while keeping it screen reader-accessible.
* Source:

.sr-only:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(100%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;

This approach has more than one issue.

[The figure element] can thus be used to annotate illustrations, diagrams, photos, code listings, etc, that are referred to from the main content of the document, but that could, without affecting the flow of the document, be moved away from that primary content, ...

HTML5: Edition for Web Authors

Khan Academy’s annual report charts are vital to the understanding of the page they’re in, and cannot be removed from the primary document without affecting it. The data inside these charts is the meat of the annual report.

So, as far as semantics are concerned, figure is not an element suitable to represent these charts.

Furthermore, the markup for the figure would have to be very dirty even if using it were possible, because the text that goes in the figcaption needs to be provided inside an aria-label on the figure alongside a role attribute for certain browser-screen-reader combinations to even announce figure as it is intended to be announced; and this brings us again to the “but the text inside figcaption is not even a label for the figure element” argument…

My friend Scott O’Hara has a wonderful article about figure and figcaption detailing how to use and not use them, and how to ensure the best cross-browser and screen reader compatibility. I highly recommend checking it out.

When it comes to accessibility, semantics matter a lot. Learning about an element’s semantics and proper usage helps us make better informed decisions as to which element to use when.

Final Words

I had great fun working on the Khan Academy annual report, and I learned quite a bit in the process. Khan Academy’s mission is to provide free education for everyone everywhere. In other words, they are working to make world-class education accessible by everyone. The least I could do is to make sure the product I helped build for them was just as accessible by everyone, regardless of their context and abilities. I’m quite proud of the work we did. And if you could use my help building better, more accessible products, get in touch.

And if you want to be the first to know when the next article comes out (hint: there will be more like this one), you can subscribe to my blog’s RSS feed.

Thank you for reading.

Further Reading

Level up your accessibility knowledge with the Practical Accessibility course!

I created a self-paced, get-right-down-to-it online video course for web designers and developers who want to start creating more accessible Web user interfaces and digital products today.

The course is now open for enrollment!

Real. Simple. Syndication.

Get my latest content in your favorite RSS reader. (What is RSS?)

Follow me on X (formerly Twitter)