Chart Library Accessibility
Permalink to "Chart Library Accessibility"Chart libraries differ more in accessibility than grid libraries do. Some ship comprehensive modules — keyboard navigation of points, screen reader sections, legend toggle buttons, sonification. Others offer a single option or nothing at all. And every library’s defaults leave the most important parts to you: what the chart is about, what its numbers mean, and how a user who cannot see it gets the data. A dashboard built from a well-configured library with summaries and tables can be fully usable without sight; the same dashboard with defaults is a row of unlabelled images.
This topic compares five widely used libraries and shows how to configure each: Highcharts, Recharts, Apache ECharts, Vega-Lite and Observable Plot. The users most affected are screen reader users (names, descriptions, data access), keyboard users (exploring values), colour-blind users (series distinction) and low-vision users (text size, contrast, zoom). The failure this topic prevents is assuming a library is “accessible” because it has an option somewhere, without configuring it or adding what it cannot provide.
This topic belongs to accessible data component libraries.
WCAG criteria in scope
Permalink to "WCAG criteria in scope"| Criterion | Level | Library features that help | What you add |
|---|---|---|---|
| 1.1.1 Non-text Content | A | Descriptions, ARIA output | Summaries and tables |
| 1.3.1 Info and Relationships | A | Labelled axes and legends | Tables with headers |
| 1.4.1 Use of Color | A | Decals, dash styles, symbols | Direct labels |
| 1.4.11 Non-text Contrast | AA | Theme options | Verified palettes |
| 2.1.1 Keyboard | A | Highcharts and Recharts navigation | Wrappers for others |
| 4.1.2 Name, Role, Value | A | Legend toggles (some libraries) | HTML toggles elsewhere |
Prerequisites
Permalink to "Prerequisites"- Data visualization & chart alternatives — summaries and tables.
- Canvas & SVG chart keyboard interaction — keyboard models.
- Chart colour & contrast — palettes and patterns.
ARIA & HTML spec reference
Permalink to "ARIA & HTML spec reference"| Output | Where it comes from | Notes |
|---|---|---|
| Chart name | Library option or wrapping figure | Always provide |
| Long description | Caption, aria-describedby, library description | Human-written summary preferred |
| Point labels | Highcharts points, Plot/Vega descriptions | Limit on dense data |
| Keyboard focus | Highcharts, Recharts layer, your wrapper | One tab stop per chart |
| Legend buttons | Highcharts, your HTML | aria-pressed |
| Data table | Library view or your HTML | Complete and labelled |
| Graphics roles | Vega output | Support varies |
Step-by-step implementation
Permalink to "Step-by-step implementation"Step 1 — Inventory
Permalink to "Step 1 — Inventory"List each library in use, its version, and its accessibility features.
Step 2 — Enable built-in features
Permalink to "Step 2 — Enable built-in features"// Highcharts: module loaded; ECharts: aria + decal; Recharts: accessibilityLayer; Plot: aria options
See Highcharts accessibility module configuration, Recharts accessibility and ECharts aria and decal patterns.
Step 3 — Summary and table for every chart (SC 1.1.1, 1.3.1)
Permalink to "Step 3 — Summary and table for every chart (SC 1.1.1, 1.3.1)"<figure aria-labelledby="c-h" aria-describedby="c-sum"><h3 id="c-h">…</h3><p id="c-sum">…</p>…<table>…</table></figure>
Step 4 — Keyboard access (SC 2.1.1)
Permalink to "Step 4 — Keyboard access (SC 2.1.1)"Use built-in navigation where it exists; elsewhere add a focusable wrapper that moves through points and announces values.
Step 5 — Colour independence (SC 1.4.1)
Permalink to "Step 5 — Colour independence (SC 1.4.1)"Dashes, symbols, decals and direct labels — configured per library. See Vega-Lite accessible output and Observable Plot aria attributes.
Step 6 — Shared defaults
Permalink to "Step 6 — Shared defaults"Wrap each library in a defaults helper or component so every chart inherits the configuration.
Keyboard interaction contract
Permalink to "Keyboard interaction contract"Aim for the same contract across libraries so users learn it once:
| Key | Action | Libraries with built-in support |
|---|---|---|
| Tab | Into the chart (one stop) | Highcharts, Recharts (layer); others via wrapper |
| Left / Right | Previous / next point | Highcharts, Recharts; others via wrapper |
| Up / Down | Previous / next series | Highcharts; others via wrapper |
| Enter on legend item | Toggle series | Highcharts; HTML toggles elsewhere |
| Escape | Leave chart navigation | Highcharts; wrapper |
Screen reader compatibility matrix
Permalink to "Screen reader compatibility matrix"| Library | NVDA | JAWS | VoiceOver | Notes |
|---|---|---|---|---|
| Highcharts | Good | Good | Good | Configure descriptions and units |
| Recharts | Tooltip announcements with layer | Same | Same | Add figure and table |
| ECharts | Description only | Same | Same | Add keyboard and table |
| Vega-Lite | Description; marks in browse mode | Partial | Partial | Table recommended |
| Observable Plot | Labels in browse mode | Partial | Partial | Table recommended |
Edge cases & failure modes
Permalink to "Edge cases & failure modes"1. Module not loaded
Permalink to "1. Module not loaded"Diagnosis: Highcharts accessibility module missing from the bundle. Fix: include it in the shared chart setup.
2. Generated descriptions too long
Permalink to "2. Generated descriptions too long"Diagnosis: ECharts lists dozens of values. Fix: human summaries.
3. Canvas renderers
Permalink to "3. Canvas renderers"Diagnosis: no mark semantics; ignores forced colours. Fix: SVG where possible; tables always.
4. Colour-only series
Permalink to "4. Colour-only series"Diagnosis: defaults everywhere. Fix: decals, dashes, symbols, labels.
5. Dense marks exposed
Permalink to "5. Dense marks exposed"Diagnosis: thousands of labelled nodes. Fix: hide dense layers; provide tables.
Highcharts accessibility module configuration
Permalink to "Highcharts accessibility module configuration"Descriptions, units, keyboard order, screen reader sections and verbosity thresholds turn good defaults into useful output. See Highcharts accessibility module configuration.
accessibility: { point: { valueSuffix: ' million euros' } }
Recharts accessibility
Permalink to "Recharts accessibility"accessibilityLayer for keyboard tooltips; figures, summaries, dashes, labels and tables around it. See Recharts accessibility.
<LineChart data={data} accessibilityLayer>…</LineChart>
ECharts aria and decal patterns
Permalink to "ECharts aria and decal patterns"aria descriptions and decal patterns built in; keyboard and tables added by you. See ECharts aria and decal patterns.
aria: { enabled: true, decal: { show: true } }
Vega-Lite accessible output
Permalink to "Vega-Lite accessible output"Descriptions, axis titles, mark descriptions, SVG rendering and tables generated from the spec’s data. See Vega-Lite accessible output.
"description": "Quarterly revenue by region, 2026."
Observable Plot aria attributes
Permalink to "Observable Plot aria attributes"ariaLabel, ariaDescription and ariaHidden on plots and marks, with tables for dense data. See Observable Plot aria attributes.
Plot.gridY({ ariaHidden: true })
Cross-cutting concerns
Permalink to "Cross-cutting concerns"One chart wrapper. Whatever the library, wrap charts in a component that requires a title and summary, renders a table toggle, provides keyboard navigation where missing, and applies colour-independent series styles. The wrapper is where consistency comes from.
Mixed libraries. Dashboards often mix libraries. Align keyboard behaviour and summary placement across them, even if internals differ.
Dark mode and forced colours. Each library themes differently; verify palettes and decals in both themes, and remember that canvas rendering ignores forced colours.
Upgrades. Accessibility features change between versions; re-test after upgrades, especially for libraries adding features quickly.
Worked example: a dashboard with three chart libraries
Permalink to "Worked example: a dashboard with three chart libraries"A product had grown a dashboard with Highcharts (finance widgets), ECharts (heatmaps) and Recharts (product analytics). Accessibility varied wildly: Highcharts widgets announced points but had no descriptions; ECharts heatmaps were unlabelled canvases; Recharts charts were hover-only. The team built a ChartFigure wrapper used by all three: required title and summary, a table toggle, a status region, and a keyboard adapter for ECharts. Each library got shared defaults (Highcharts units and order, ECharts aria and decals with SVG, Recharts accessibilityLayer with dashes). The dashboard now behaves consistently, and the table toggles became the most-used feature among analysts.
Who is affected, and how
Permalink to "Who is affected, and how"| User group | Library default failure | Fix |
|---|---|---|
| Screen reader users | Unlabelled graphics; no data | Summaries and tables |
| Keyboard users | Hover-only values | Built-in or wrapper navigation |
| Colour-blind users | Colour-only series | Decals, dashes, symbols, labels |
| Low-vision users | Small canvas text; contrast | SVG rendering; verified palettes |
| Everyone | Unclear message | Visible summaries |
Evaluating a chart library
Permalink to "Evaluating a chart library"Before adopting a chart library, build one line chart and one bar chart with realistic data and check: can you name and describe the chart? Can a keyboard user reach values? Can you distinguish series without colour? Can you produce a table from the same data easily? Does SVG rendering exist? How does the library behave in dark mode and forced colours? Spend fifteen minutes with a screen reader. A library that needs only a thin wrapper to pass all of these is a good choice; one that needs extensive workarounds will cost you on every chart.
An audit script for existing dashboards
Permalink to "An audit script for existing dashboards"List every chart and its library. For each: check the accessible name in the accessibility tree; check for a visible summary; check for a table; try the keyboard; take a greyscale screenshot. Record results in a simple table. Most dashboards show the same two gaps — no summaries and no tables — which a shared wrapper fixes across all charts at once.
Choosing between libraries for new work
Permalink to "Choosing between libraries for new work"For new dashboards, pick the library whose built-in accessibility covers the most of what you need, then standardise on it. Teams prioritising accessibility with minimal custom code often choose Highcharts; teams wanting open-source and declarative specs often choose Vega-Lite or Observable Plot with a wrapper; React teams with simple needs often choose Recharts with the accessibility layer and a wrapper. Whatever the choice, the wrapper is not optional.
Design system integration
Permalink to "Design system integration"Provide one ChartFigure component and per-library defaults modules. Require summaries, tables and series styles; supply keyboard adapters for libraries without navigation; and document which library to use for which chart types. Keep a compatibility table of library versions and verified features.
Common mistakes with chart libraries
Permalink to "Common mistakes with chart libraries"- Options never enabled (modules not loaded, aria off).
- Generated text instead of summaries.
- No table.
- Canvas everywhere.
- Different keyboard behaviour per library.
Measuring chart accessibility
Permalink to "Measuring chart accessibility"For every chart in a product, record: summary present, table available, keyboard access, colour-independent series, and last screen reader check. A product-wide percentage for each column shows where to invest, and per-library breakdowns show which wrappers need work.
A minimal accessible chart, regardless of library
Permalink to "A minimal accessible chart, regardless of library"Every chart in a product should meet the same minimum: a heading that names it; a one- or two-sentence visible summary of its main finding; a way to see the data as a table; series distinguishable without colour; values reachable from the keyboard either in the chart or in the table; and a focus indicator wherever focus can land. If a library makes any of these hard, the wrapper supplies it. Publishing this minimum as a checklist in the design system documentation turns chart accessibility from a library debate into a clear definition of done.
Testing checklist
Permalink to "Testing checklist"Automated
Permalink to "Automated"Keyboard
Permalink to "Keyboard"Screen reader and visual
Permalink to "Screen reader and visual"FAQ
Permalink to "FAQ"Which chart library is most accessible?
Highcharts has the most comprehensive built-in support. Others can be made accessible with wrappers, summaries and tables.
Is a data table enough?
A table is a complete equivalent for the data; a summary conveys the message; keyboard exploration helps in place. Provide all three where possible.
Should I use canvas or SVG?
SVG for most dashboards; canvas for very large datasets, with tables as the main accessible route.
Do generated descriptions satisfy WCAG?
They name and partly describe the chart, but a human summary of the finding is far more useful.
How do I handle many charts on one page?
Headings per chart, consistent summaries and keyboard behaviour, and tables behind toggles.
How do I test chart libraries quickly?
Turn on a screen reader, tab to each chart, arrow through points, toggle a series, open the table — the same five steps for every library.
Should we standardise on one library?
It helps consistency, but a shared wrapper can align behaviour across several.
What about sonification?
Highcharts supports it; it is a useful addition for trends, never a replacement for tables.
Who should own chart accessibility?
The team that owns the chart wrapper and library defaults, usually the design system or a data visualisation platform team, with product teams writing summaries for their charts.
How do we write good summaries at scale?
Generate the factual parts (largest, smallest, change) from data and let authors add the interpretation for important charts.
Are library accessibility modules enough for procurement?
They support conformance claims only when configured and tested in your product. Report actual behaviour in your ACR, not library marketing.
What should we do with charts we cannot fix soon?
Add a summary and a table first; they make the information available even before keyboard and colour work is done.
Related
Permalink to "Related"- Data visualization & chart alternatives — principles
- Chart type-specific patterns — per-type guidance
- Interactive chart controls — zoom, brush, legends
- React data grid libraries — the grid side of dashboards
- Design system tokens & component contracts — wrappers and contracts