Agent Wranglers

AXS-65Recommended

Give every chart a summary and its numbers

Give every chart a short name, a caption that states its main finding, and the numbers behind it as a table or a download. This is WCAG criterion 1.1.1 (A).

How to do it

The W3C tutorial on complex images splits the text alternative in two parts. A short one names the chart, and a long one carries the data. Put the chart in a figure whose figcaption says what the reader should take away. Put the numbers in a table under it or inside a details element, built as Give tables headers says. Give an SVG chart role="img" and an aria-label, and a canvas chart fallback text. Avoid aria-describedby for the data, since screen readers read the target as one paragraph and lose the table. Lines and bars also need a second cue besides colour, as Never use colour as the only signal says.

Examples

HTML example

<figure class="chart">
  <svg role="img" aria-label="Monthly orders, January to June">…</svg>
  <figcaption>Orders grew from 120 in January to 310 in June.</figcaption>
  <details>
    <summary>Show the numbers</summary>
    <table>
      <thead><tr><th scope="col">Month</th><th scope="col">Orders</th></tr></thead>
      <tbody><tr><th scope="row">January</th><td>120</td></tr></tbody>
    </table>
  </details>
</figure>

JavaScript example

// Playwright: every chart has a name and its data nearby
for (const chart of await page.locator('svg[role="img"], canvas, img.chart').all()) {
  await expect(chart).toHaveAccessibleName(/\S/);
  const figure = chart.locator('xpath=ancestor::figure[1]');
  await expect(figure.locator('figcaption')).toHaveCount(1);
  expect(await figure.locator('table, a[href$=".csv"]').count()).toBeGreaterThan(0);
}

Python example

# Playwright for Python: the same check
for chart in page.locator('svg[role="img"], canvas, img.chart').all():
    expect(chart).to_have_accessible_name(re.compile(r"\S"))
    figure = chart.locator("xpath=ancestor::figure[1]")
    expect(figure.locator("figcaption")).to_have_count(1)
    assert figure.locator('table, a[href$=".csv"]').count() > 0

How to check

A browser test finds every chart (canvas, chart svg or chart image) on each page type. Each has a non-empty accessible name and sits in a figure that holds a figcaption and a table or a link to the data.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/accessibility/seeing-and-reading/chart-alternatives">Agent Wranglers accessibility playbook</a>. In code you write, add a comment next to it with the same link.