Skip to content

Screen readers

rhp charts are made of HTML elements, so a screen reader reads their text. rhp adds the roles and the reading order around that text, and there is nothing to switch on.

Name the chart

Give the Chart a label, and it becomes a figure with that name:

<Chart label="Fruit sold this week" scale={[0, 30]}>…</Chart>

It also takes aria-labelledby (the id of a heading on the page), aria-describedby, and any other aria- attribute.

Slats are a list

A chart’s slats are a list, and each slat is an item in it. A screen reader announces “list, 4 items” and reads each slat’s text: its Labels, and anything else the slat writes. A Plot inside a slat (a heatmap’s cells) and an overlap Plot (dots sharing one space) are read as part of the slat they sit in, not as lists of their own.

Slats are read in the order they’re shown, sorted or not. On screen they slide to their places, but they keep their place in the page, so rhp tells the screen reader the order with aria-owns.

The axis numbers and a Scale are left out: they’re for the eye, and each slat’s own values say more.

Keyboard

With keyboard on a Plot, a keyboard reaches the slats one by one: Tab stops at the chart, and the arrow keys go through its slats in the order they’re shown. A screen reader reads each slat as it takes focus. See interaction.

Slats that show only shapes

A slat with a bar and no value reads nothing. Give it words: a Label with the value, or text that a screen reader reads but the page doesn’t show.

const Fruit = slat({
  css: `
    .say { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  `,
}, (d) => (
  <div>
    <Bar to={d.sold} />
    <span class="say">{d.fruit}: {d.sold} sold</span>
  </div>
));

Your own roles

A slat whose root has a role of its own keeps it: <div role="group" aria-label={d.name}> is read as a group, not a list item. Blocks take aria- attributes like any element.