Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(a11y): support ARIA attributes, role and fallback content for canvas #1061

Merged
merged 1 commit into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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