How We Engineered a Universal Chart Accessibility Engine
Screen readers usually see charts as blank images. We built an engine that visually reads SVG geometry to automatically generate accessibility data tables.
How We Engineered a Universal Chart Accessibility Engine
Data visualization is one of the hardest problems in web accessibility. Screen readers see a chart as an image or a collection of meaningless shapes. Standard advice is "add anaria-label" or "provide a data table," but that puts the burden on developers to manually annotate every single chart—and they often don't.
We wanted a solution that works automatically, with zero configuration. To do that, we had to build an engine that doesn't just look for code; it "reads" the chart visually, just like a human does.
Here is the technical deep dive into how our Chart Accessibility engine works.
1. Detection: Beyond Just<svg>
The first challenge is knowing what is a chart and what is just an icon. We use a multi-layered detection strategy:
- Library Fingerprinting: We detect specific class names and structures from popular libraries likeRecharts,Chart.js,Highcharts,ApexCharts,D3, andVictory.
- Heuristic Analysis: For custom or raw SVGs, we analyze the geometry. We count "bar-like" rectangles, look for "data-dense" paths, and identify axis patterns (e.g., a group of text elements aligned at the bottom or left).
2. The Core Innovation: Visual Estimation Logic
This is where the magic happens. Most accessibility tools stop if they can't find semantic data attributes. We go further.
When a chart is rendered as an SVG, the data values are baked into the geometry. A bar representing "100" isn't stored asvalue="100"; it's drawn as a<rect>withheight="200px".
Our engine reverse-engineers the data from these pixels:
Step A: Establishing the Scale
We scan the Y-axis for text labels. If we find "0", "50", "100" aligned vertically, we calculate thepixel-to-value ratio. We determine exactly how many pixels represent one unit of data.
// Simplified logic
const pixelHeight = axisBottomY - axisTopY; // e.g., 300px
const valueRange = maxValue - minValue; // e.g., 100 units
const scaleRatio = valueRange / pixelHeight; // 0.33 units per pixel
Step B: Geometric Measurement
We then measure the bounding box of every data element (bars, points, or line segments). usinggetBoundingClientRect(). By comparing a bar's height or a point's Y-position against our established scale, we can mathematically reconstruct the original data value with high precision.
This allows us to extract accurate data fromanySVG chart, even if the developer completely forgot to add accessibility tags.
3. Synthesis: Creating the Experience
Once we have the data, we don't just dump it. We create a rich, accessible experience that sits "on top" of the visual chart.
- Keyboard Navigation: We inject a "View Data" button that is keyboard accessible.
- Hidden Data Table: We generate a semantic HTML
<table>containing all the extracted data. This is the gold standard for screen reader accessibility, allowing users to navigate by row and column. - Smart Summaries: We generate a natural language summary using simple statistical analysis. "Bar chart with 5 data points. Trending up. Maximum value 500 at 'May'."
Conclusion
Accessibility shouldn't rely on developers doing everything perfectly. By using intelligent DOM analysis and visual estimation logic, we can bridge the gap between visual data and semantic code, making the web's data verifiable and understandable for everyone.