Skip to content
quartiledocsv0.1
GitHub

Accessible charts

Use chart summaries, keyboard navigation and exact table alternatives to make analysis understandable. Sparkline supplies a compact image summary instead.

Name every chart

A chart is a figure named by aria-label; without one it is named after its type (“Line chart”). Name what it shows and for when, as you would in a card title. The summary underneath is written from the field labels and formats, so declare those once.

// dailyRows is preaggregated: one row per date.
// The summary and the table read field labels and formats, so name them once.
const daily = dataset(dailyRows, {
  amount: { label: 'Revenue', format: 'currency' },
  conversion_rate: { label: 'Conversion', format: 'percent' },
});

<LineChart data={daily} x="date" y="amount" aria-label="Revenue per day, Sep 7 to Oct 6, 2026" />
// Hidden summary: "Revenue from Sep 7 to Oct 6: up …%, from $… to $…. Low $… on …; high $… on …."

Offer the table

view="table" shows the chart's exact values to everyone, at the chart's size, with the same formats. A Chart / Table switch helps anyone who wants exact numbers. Scatter plots above 200 visible points provide a built-in data-view button and 50-row pages; smaller plots keep the hidden table. Each row remains reachable without constructing a full hidden DOM table.

5 bars. Highest North America at $160.0K; lowest Middle East & Africa at $19.1K.

Revenue by region, Sep 7 to Oct 6, 2026
RegionRevenue
Asia Pacific$68.7K
North America$160.0K
Latin America$31.8K
Middle East & Africa$19.1K
Europe$104.0K
const [view, setView] = useState('chart');

<SegmentedControl
  aria-label="Show as"
  size="sm"
  options={[{ value: 'chart', label: 'Chart' }, { value: 'table', label: 'Table' }]}
  value={view}
  onChange={setView}
/>
<BarChart
  data={orders}
  x="region"
  y="amount"
  orientation="horizontal"
  format="currency-compact"
  view={view}
  aria-label="Revenue by region, Sep 7 to Oct 6, 2026"
/>

Keep the keyboard path short

Each chart's plot is one tab stop; arrow keys move inside it. That keeps a dashboard of ten charts at ten tab stops, not hundreds. Two things help further:

  • Put filters before the charts in the DOM, so keyboard users set the context first.
  • Use select or brush only where publishing helps; a chart without them is still navigable and announces each point.

Do not rely on color

  • Label series directly or keep the legend on (it is on by default for two or more series), and keep the number of colors small.
  • Deltas carry a sign as well as a color; badges carry a word. Keep that when you build your own cells.
  • If you override the categorical tokens (--q-cat-1 to --q-cat-8), check contrast against --q-surface in both themes.

Sparklines need numbers beside them

A Sparkline is an image with a summary in its accessible name. It has no table and no keyboard model, so always show the figure it summarizes next to it, as KPI and the DataTable sparkline cell do.

Test it

With a keyboard

Tab through the page. Every interactive chart should take focus once, arrow keys should move through its points, and the focused value should show in the tooltip.

With a screen reader

Quartile's summaries and tables have not been tested with NVDA, JAWS or VoiceOver yet. If you test them, report what you find; it is the most useful contribution right now.

Report an issueBuilt Oct 21, 2026