Skip to content

Commit

Permalink
feat(a11y): support ARIA attributes, role and fallback content for ca…
Browse files Browse the repository at this point in the history
…nvas (#1061)
  • Loading branch information
d-koppenhagen authored Dec 5, 2023
1 parent 72da745 commit c1ee49d
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 11 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ Need an API to fetch data? Consider [Cube](https://cube.dev/?ref=eco-vue-chartjs

- [Reactivity](https://vue-chartjs.org/guide/#updating-charts)
- [Access to Chart instance](https://vue-chartjs.org/guide/#access-to-chart-instance)
- [Accessibility](https://vue-chartjs.org/guide/#accessibility)
- [Migration from v4 to v5](https://vue-chartjs.org/migration-guides/#migration-from-v4-to-v5/)
- [Migration from vue-chart-3](https://vue-chartjs.org/migration-guides/#migration-from-vue-chart-3/)
- [API](https://vue-chartjs.org/api/)
Expand Down
28 changes: 18 additions & 10 deletions src/chart.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { Chart as ChartJS } from 'chart.js'
import {
defineComponent,
ref,
shallowRef,
h,
onMounted,
nextTick,
onBeforeUnmount,
watch,
onMounted,
ref,
shallowRef,
toRaw,
nextTick
watch
} from 'vue'
import { Chart as ChartJS } from 'chart.js'

import type { ChartComponent } from './types.js'
import { Props } from './props.js'
import {
Expand All @@ -23,7 +24,7 @@ import {

export const Chart = defineComponent({
props: Props,
setup(props, { expose }) {
setup(props, { expose, slots }) {
const canvasRef = ref<HTMLCanvasElement | null>(null)
const chartRef = shallowRef<ChartJS | null>(null)

Expand Down Expand Up @@ -112,9 +113,16 @@ export const Chart = defineComponent({
)

return () => {
return h('canvas', {
ref: canvasRef
})
return h(
'canvas',
{
role: 'img',
ariaLabel: props.ariaLabel,
ariaDescribedby: props.ariaDescribedby,
ref: canvasRef
},
[h('p', {}, [slots.default ? slots.default() : ''])]
)
}
}
}) as ChartComponent
12 changes: 11 additions & 1 deletion src/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,20 @@ export const CommonProps = {
}
} as const

export const A11yProps = {
ariaLabel: {
type: String
},
ariaDescribedby: {
type: String
}
} as const

export const Props = {
type: {
type: String as PropType<ChartType>,
required: true
},
...CommonProps
...CommonProps,
...A11yProps
} as const
2 changes: 2 additions & 0 deletions website/src/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Some basic props are defined in the components provided by `vue-chartjs`.
| datasetIdKey | Key name to identify the dataset |
| plugins | Plugins array that is passed into the Chart.js chart |
| updateMode | Mode string to indicate the transition configuration to be used. |
| ariaLabel | An [ARIA label](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label) that describes the chart to make it accessible. |
| ariaDescribedby | A reference to the [describing element](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-describedby). E. g. a table representation of the data. |

The rest of the props will fall through to the canvas element.

Expand Down
52 changes: 52 additions & 0 deletions website/src/guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,58 @@ In Vue3 projects:
const chartInstance = this.$refs.bar.chart
```

## Accessibility

To make your charts accessible to all users, you should label your charts.
Please refer also to the official [Chart.js Accessibility notes](https://www.chartjs.org/docs/latest/general/accessibility.html).

### `aria-label`

You can directly label a chart by passing an `aria-label` prop.

```vue
<template>
<BarChart aria-label="Sales figures for the years 2022 to 2024. Sales in 2022: 987, Sales in 2023: 1209, Sales in 2024: 825." />
</template>
```

### `aria-describedby`

You can reference to a describing element such as a table which describes the data by using the `aria-describedby` property.

```vue
<template>
<BarChart aria-describedby="my-data-table" />
<table id="my-data-table">
<caption>Sales figures for the years 2022 to 2024.</caption>
<thead>
<tr>
<th>2022</th>
<th>2023</th>
<th>2024</th>
</tr>
</thead>
<tbody>
<tr>
<td>987</td>
<td>1209</td>
<td>825</td>
</tr>
</tbody>
</table>
</template>
```

### Fallback-Content

In case the Browser is not able to render the `canvas` element, you should consider providing fallback content by using the Slot of each component.

```vue
<template>
<BarChart>Chart couldn't be loaded.</BarChart>
</template>
```

## Examples

### Chart with props
Expand Down

0 comments on commit c1ee49d

Please sign in to comment.