Skip to content

Commit c1ee49d

Browse files
feat(a11y): support ARIA attributes, role and fallback content for canvas (#1061)
1 parent 72da745 commit c1ee49d

File tree

5 files changed

+84
-11
lines changed

5 files changed

+84
-11
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ Need an API to fetch data? Consider [Cube](https://cube.dev/?ref=eco-vue-chartjs
9292

9393
- [Reactivity](https://vue-chartjs.org/guide/#updating-charts)
9494
- [Access to Chart instance](https://vue-chartjs.org/guide/#access-to-chart-instance)
95+
- [Accessibility](https://vue-chartjs.org/guide/#accessibility)
9596
- [Migration from v4 to v5](https://vue-chartjs.org/migration-guides/#migration-from-v4-to-v5/)
9697
- [Migration from vue-chart-3](https://vue-chartjs.org/migration-guides/#migration-from-vue-chart-3/)
9798
- [API](https://vue-chartjs.org/api/)

src/chart.ts

+18-10
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1+
import { Chart as ChartJS } from 'chart.js'
12
import {
23
defineComponent,
3-
ref,
4-
shallowRef,
54
h,
6-
onMounted,
5+
nextTick,
76
onBeforeUnmount,
8-
watch,
7+
onMounted,
8+
ref,
9+
shallowRef,
910
toRaw,
10-
nextTick
11+
watch
1112
} from 'vue'
12-
import { Chart as ChartJS } from 'chart.js'
13+
1314
import type { ChartComponent } from './types.js'
1415
import { Props } from './props.js'
1516
import {
@@ -23,7 +24,7 @@ import {
2324

2425
export const Chart = defineComponent({
2526
props: Props,
26-
setup(props, { expose }) {
27+
setup(props, { expose, slots }) {
2728
const canvasRef = ref<HTMLCanvasElement | null>(null)
2829
const chartRef = shallowRef<ChartJS | null>(null)
2930

@@ -112,9 +113,16 @@ export const Chart = defineComponent({
112113
)
113114

114115
return () => {
115-
return h('canvas', {
116-
ref: canvasRef
117-
})
116+
return h(
117+
'canvas',
118+
{
119+
role: 'img',
120+
ariaLabel: props.ariaLabel,
121+
ariaDescribedby: props.ariaDescribedby,
122+
ref: canvasRef
123+
},
124+
[h('p', {}, [slots.default ? slots.default() : ''])]
125+
)
118126
}
119127
}
120128
}) as ChartComponent

src/props.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,20 @@ export const CommonProps = {
3030
}
3131
} as const
3232

33+
export const A11yProps = {
34+
ariaLabel: {
35+
type: String
36+
},
37+
ariaDescribedby: {
38+
type: String
39+
}
40+
} as const
41+
3342
export const Props = {
3443
type: {
3544
type: String as PropType<ChartType>,
3645
required: true
3746
},
38-
...CommonProps
47+
...CommonProps,
48+
...A11yProps
3949
} as const

website/src/api/index.md

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Some basic props are defined in the components provided by `vue-chartjs`.
1111
| datasetIdKey | Key name to identify the dataset |
1212
| plugins | Plugins array that is passed into the Chart.js chart |
1313
| updateMode | Mode string to indicate the transition configuration to be used. |
14+
| 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. |
15+
| 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. |
1416

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

website/src/guide/index.md

+52
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,58 @@ In Vue3 projects:
141141
const chartInstance = this.$refs.bar.chart
142142
```
143143

144+
## Accessibility
145+
146+
To make your charts accessible to all users, you should label your charts.
147+
Please refer also to the official [Chart.js Accessibility notes](https://www.chartjs.org/docs/latest/general/accessibility.html).
148+
149+
### `aria-label`
150+
151+
You can directly label a chart by passing an `aria-label` prop.
152+
153+
```vue
154+
<template>
155+
<BarChart aria-label="Sales figures for the years 2022 to 2024. Sales in 2022: 987, Sales in 2023: 1209, Sales in 2024: 825." />
156+
</template>
157+
```
158+
159+
### `aria-describedby`
160+
161+
You can reference to a describing element such as a table which describes the data by using the `aria-describedby` property.
162+
163+
```vue
164+
<template>
165+
<BarChart aria-describedby="my-data-table" />
166+
<table id="my-data-table">
167+
<caption>Sales figures for the years 2022 to 2024.</caption>
168+
<thead>
169+
<tr>
170+
<th>2022</th>
171+
<th>2023</th>
172+
<th>2024</th>
173+
</tr>
174+
</thead>
175+
<tbody>
176+
<tr>
177+
<td>987</td>
178+
<td>1209</td>
179+
<td>825</td>
180+
</tr>
181+
</tbody>
182+
</table>
183+
</template>
184+
```
185+
186+
### Fallback-Content
187+
188+
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.
189+
190+
```vue
191+
<template>
192+
<BarChart>Chart couldn't be loaded.</BarChart>
193+
</template>
194+
```
195+
144196
## Examples
145197

146198
### Chart with props

0 commit comments

Comments
 (0)