Chart.js Accessibility — Making Charts Usable for Everyone
In this tutorial, you will learn about Chart.js Accessibility. We cover key concepts, practical examples, and best practices to help you master this topic.
Chart.js accessibility ensures charts are usable by people with visual, motor, and cognitive disabilities through ARIA attributes, keyboard navigation, and fallback data tables.
What You'll Learn
By the end of this guide, you will add ARIA labels and descriptions to charts, implement keyboard navigation for data points, use high-contrast color schemes, generate accessible data tables, and test with screen readers.
ARIA Labels
var ctx = document.getElementById('myChart');
ctx.setAttribute('role', 'img');
ctx.setAttribute('aria-label', 'Bar chart showing quarterly sales for 2025');
new Chart(ctx, {
type: 'bar',
data: { ... },
options: {
responsive: true
}
});
Fallback Data Table
function createDataTable(chart) {
var table = document.createElement('table');
table.setAttribute('aria-label', 'Chart data table');
var caption = table.createCaption();
caption.textContent = chart.canvas.getAttribute('aria-label');
var header = table.insertRow();
header.insertCell().textContent = 'Label';
chart.data.datasets.forEach(function(ds) {
header.insertCell().textContent = ds.label;
});
chart.data.labels.forEach(function(label, i) {
var row = table.insertRow();
row.insertCell().textContent = label;
chart.data.datasets.forEach(function(ds) {
row.insertCell().textContent = ds.data[i];
});
});
document.getElementById('data-table-container').appendChild(table);
}
High Contrast Colors
var accessibleColors = ['#006bb3', '#e67e00', '#2d6a4f', '#9b2226', '#6c4f3d'];
new Chart(ctx, {
type: 'bar',
data: {
datasets: [{
backgroundColor: accessibleColors[0]
}]
}
});
Common Mistakes
1. Missing ARIA Labels on Canvas
Canvas elements are invisible to screen readers by default. Always set role and aria-label.
2. Relying Only on Color
Color-only encoding excludes color-blind users. Add patterns, labels, or different shapes.
3. No Keyboard Navigation
Users with motor impairments may not use a mouse. Provide tabIndex and keyboard event handlers.
4. Low Contrast Text
Light gray text on white background fails WCAG contrast ratio. Use minimum 4.5:1 contrast.
5. No Data Table Fallback
Screen readers struggle with complex chart data. Provide an HTML data table alongside the chart.
Practice Questions
Q1: What ARIA attribute makes a canvas accessible? A: role="img" and aria-label with a description of the chart content.
Q2: What is the minimum WCAG contrast ratio for text? A: 4.5:1 for normal text, 3:1 for large text (18px+).
Q3: How do you make chart elements keyboard-navigable? A: Set tabIndex on canvas and handle keydown events for Enter and Arrow keys.
Q4: What is a fallback data table? A: An HTML table containing the same data as the chart, hidden visually but available to screen readers.
Q5: How do you test chart accessibility? A: Use a screen reader (VoiceOver, NVDA), axe DevTools, and Lighthouse accessibility audit.
Challenge: Build a chart with all accessibility features: ARIA labels, keyboard navigation that highlights data points on focus, a visible data table, and a toggle for high-contrast mode.
FAQ
Try It Yourself
Build an accessible chart with data table.
<!DOCTYPE html>
<html>
<head>
<title>Accessible Chart Demo</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body { font-family: sans-serif; padding: 20px; }
table { width: 100%; max-width: 500px; border-collapse: collapse; margin-top: 20px; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f5f5f5; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); }
</style>
</head>
<body>
<h2>Accessible Chart</h2>
<canvas id="a11yChart" width="500" height="300" role="img" aria-label="Quarterly revenue for Fiscal Year 2025 showing Q1: 30K, Q2: 45K, Q3: 40K, Q4: 60K"></canvas>
<div id="table-container" aria-hidden="true"></div>
<script>
var ctx = document.getElementById('a11yChart');
var chart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
datasets: [{
label: 'Revenue',
data: [30, 45, 40, 60],
backgroundColor: ['#006bb3', '#e67e00', '#2d6a4f', '#9b2226']
}]
},
options: {
responsive: true,
plugins: {
legend: { labels: { color: '#333' } }
},
scales: {
x: { ticks: { color: '#333' } },
y: { ticks: { color: '#333' } }
}
}
});
function buildFallbackTable() {
var container = document.getElementById('table-container');
var table = document.createElement('table');
table.setAttribute('tabindex', '0');
var caption = table.createCaption();
caption.textContent = 'Quarterly Revenue - Fiscal Year 2025';
var header = table.insertRow();
header.insertCell().textContent = 'Quarter';
chart.data.datasets.forEach(function(ds) {
header.insertCell().textContent = ds.label + ' ($K)';
});
chart.data.labels.forEach(function(label, i) {
var row = table.insertRow();
row.insertCell().textContent = label;
chart.data.datasets.forEach(function(ds) {
row.insertCell().textContent = ds.data[i];
});
});
container.appendChild(table);
}
buildFallbackTable();
</script>
</body>
</html>
What's Next
Build a complete dashboard project.
Project — Full dashboard project.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro