Naming Charts and Figures with figcaption
Permalink to "Naming Charts and Figures with figcaption"A chart without a name is announced as “graphic” or not at all. A chart named “Chart 1” is barely better. Charts need a short name that says what they show (“Monthly revenue, 2025”) and a caption that says what matters (“Revenue rose 18% after the March launch”). HTML gives you figure and figcaption for exactly this, and SVG charts can point aria-labelledby at the visible title. Getting the combination right avoids both silence and the common double announcement.
This guide belongs to accessible names and descriptions for data widgets.
Spec reference
Permalink to "Spec reference"- HTML figure / figcaption —
figcaptionprovides the accessible name offigurewhen no other name is set. - SC 1.1.1 Non-text Content (A) — charts need text alternatives that identify them and convey the key information.
- SC 1.3.1 (A) — caption programmatically associated with its chart.
- ARIA —
role="img"on an SVG witharia-labelledbyoraria-label;aria-describedbyfor a longer description.
When to use — and when not to
Permalink to "When to use — and when not to"Use figure and figcaption for every chart that sits in content: reports, dashboards, articles. On dense dashboards, a visible heading per widget can replace figcaption, with the chart named by that heading.
Do not repeat the same text in the figure name, the SVG name and an aria-label; screen readers will read it two or three times. The misapplication: alt-style text on the SVG that lists every data point, making a forty-second announcement users cannot skip.
Annotated code example
Permalink to "Annotated code example"<figure aria-labelledby="rev-cap">
<svg role="img" aria-labelledby="rev-title" aria-describedby="rev-sum" viewBox="0 0 640 320">
<title id="rev-title">Monthly revenue, 2025</title> <!-- short name -->
…bars…
</svg>
<figcaption id="rev-cap">
<strong>Monthly revenue, 2025.</strong>
<span id="rev-sum">Revenue rose 18% after the March launch and peaked in October.</span> <!-- takeaway -->
<a href="#rev-table">View the data table</a>
</figcaption>
</figure>
<!-- Canvas chart: name the canvas, describe via caption -->
<figure>
<canvas role="img" aria-label="Monthly revenue, 2025" aria-describedby="rev-sum2"></canvas>
<figcaption id="rev-sum2">Revenue rose 18% after the March launch.</figcaption>
</figure>
Keyboard & AT behaviour
Permalink to "Keyboard & AT behaviour"| Screen reader | On the figure | On the SVG |
|---|---|---|
| NVDA + Firefox | “figure, Monthly revenue, 2025 …” | “Monthly revenue, 2025, graphic” + description |
| JAWS + Chrome | “figure” + caption | “graphic, Monthly revenue, 2025” |
| VoiceOver + Safari | “Monthly revenue, 2025, figure” | “image” + name |
| Graphics navigation (G) | Jumps to the SVG | Name read |
Step-by-step implementation
Permalink to "Step-by-step implementation"- Write the name first. Subject, measure and period: “Monthly revenue, 2025”. Avoid “chart of” — screen readers already say graphic or image.
- Write the takeaway. One or two sentences: the trend, the comparison or the outlier that the chart exists to show.
- Wire up references. Give the SVG
role="img",aria-labelledbypointing at its title, andaria-describedbypointing at the takeaway. Hide decorative inner elements witharia-hiddenif they would otherwise be read. - Add the route to data. Link to a data table on the same page, or a toggle that shows it.
- Check for duplicates. Listen to the figure in two screen readers. If the name is read twice, remove the figure’s explicit label and let figcaption name it, or vice versa.
Integration context
Permalink to "Integration context"Writing the takeaway is covered in writing chart summaries and key takeaways, and longer descriptions in long descriptions for complex charts. Grid naming follows labelling grids with aria-labelledby. Chart library defaults are compared in chart library accessibility.
Gotchas
Permalink to "Gotchas"SVG title tooltips. A <title> element shows as a tooltip on hover in some browsers; that is usually acceptable, but if not, use aria-label instead.
Interactive charts. If the chart has focusable data points, role="img" hides them; use role="group" or role="application" with a name instead.
Figure without caption. A figure with no figcaption and no label is announced as an unnamed figure; always name it.
Edge cases
Permalink to "Edge cases"- Small multiples. Name the group figure (“Revenue by region”) and each small chart (“North”).
- Live charts. If the takeaway changes with data, update the description text, but do not announce it on every update.
- Charts in tables. Sparklines in cells need short names such as “Trend: rising” and nothing more.
Worked example
Permalink to "Worked example"A quarterly report site embedded twenty SVG charts with no names. NVDA users heard “graphic” twenty times, and some charts read out every axis tick. The team wrapped each in a figure with a caption containing a short name and a one-sentence takeaway, added role="img" with aria-labelledby and aria-describedby, hid tick labels from assistive technology and linked each chart to its data table. Reviewers using screen readers could now skim the report by graphics.
Common mistakes
Permalink to "Common mistakes"- No name, or “Chart 1”.
- Data points in the name.
- Names duplicated across figure and SVG.
- No route to the underlying data.
Testing checklist
Permalink to "Testing checklist"Testing it with a screen reader
Permalink to "Testing it with a screen reader"With NVDA in browse mode, press G to move through graphics and listen to each chart’s name; each should be specific and read once. Press Down Arrow to hear the description and confirm the data table link follows. In JAWS, list graphics with Insert+Ctrl+G and check that names are unique. In VoiceOver, use the rotor’s images list. Then open the accessibility tree in browser developer tools and verify the computed name and description of each SVG match what you intended.
Design system notes
Permalink to "Design system notes"Make the chart component require title and summary props, render the figure structure automatically and fail a lint check when either is missing.
Writing names for dashboards
Permalink to "Writing names for dashboards"Dashboards multiply the naming problem: twelve widgets, each with a chart, a title bar and sometimes a menu. Decide on one naming source per widget. The usual choice is the widget’s visible heading, which names the region (with aria-labelledby on the widget container) and the chart inside it. The chart’s own name can then be shorter (“Trend”) because the region supplies context, or it can repeat the heading when charts are reachable on their own through graphics navigation. Avoid timestamps and filter descriptions in names; they change and make every announcement longer. Put them in the description or in visible text near the chart. Finally, keep names stable when data refreshes, so users who return to a widget recognise it by the same words.
FAQ
Permalink to "FAQ"Should I use figcaption or aria-label?
Prefer visible figcaption; it helps everyone. Use aria-label only when no visible caption fits.
Is the SVG title element enough?
Combined with role img and aria-labelledby, it is reliable; alone, support varies.
How long should the name be?
A few words. Put detail in the description.
Should the caption repeat the heading?
No. If a heading names the chart, let the caption carry the takeaway.
What about decorative charts?
Truly decorative graphics get aria-hidden, but data charts are almost never decorative.
Do I still need a data table?
Yes, for anyone who needs exact values.
Related
Permalink to "Related"- Writing chart summaries and key takeaways — what to say
- Long descriptions for complex charts — when a sentence is not enough
- Labelling grids with aria-labelledby — naming other data widgets