-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
[charts] Introduce keyboard navigation #19155
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
Changes from 12 commits
d6dd42e
3cb42a7
83acf89
b54144d
db812d7
a0848e1
e30dee1
780c2a0
41d8af8
34c5e57
50fb051
8173991
0683667
24590ec
ae974da
8639c34
df1096e
302d411
cf1dcce
ec366fe
a62690a
4117d87
8e7536a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,73 @@ | ||||||
| --- | ||||||
| productId: x-charts | ||||||
| title: Charts - Accessibility | ||||||
| packageName: '@mui/x-charts' | ||||||
| --- | ||||||
|
|
||||||
| # Accessibility | ||||||
|
|
||||||
| <p class="description">Learn how the Charts implement accessibility features and guidelines, including keyboard navigation that follows international standards.</p> | ||||||
|
|
||||||
| :::info | ||||||
| A common misconception about accessibility is to only consider blind people and the screen reader. | ||||||
| But there are other disability to consider, like: | ||||||
|
|
||||||
| - **Color blindness**, making it hard to distinguish different series, or low contrast elements. | ||||||
| - **Motion disability**, making it hard to open the tooltip on a given item. | ||||||
| - **Cognitive disability**, making it hard to focus your attention on some details. | ||||||
| - **Vestibular dysfunction**, making you unconformable with animations. | ||||||
alexfauquette marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
|
|
||||||
| ::: | ||||||
|
|
||||||
| ## Guidelines | ||||||
|
|
||||||
| Common conformance guidelines for accessibility include: | ||||||
|
|
||||||
| - Globally accepted standard: [WCAG](https://www.w3.org/WAI/standards-guidelines/wcag/) | ||||||
| - US: | ||||||
| - [ADA](https://www.ada.gov/) - US Department of Justice | ||||||
|
Check warning on line 28 in docs/data/charts/accessibility/accessibility.md
|
||||||
| - [Section 508](https://www.section508.gov/) - US federal agencies | ||||||
|
Check warning on line 29 in docs/data/charts/accessibility/accessibility.md
|
||||||
| - Europe: [EAA](https://employment-social-affairs.ec.europa.eu/policies-and-activities/social-protection-social-inclusion/persons-disabilities/union-equality-strategy-rights-persons-disabilities-2021-2030/european-accessibility-act_en) (European Accessibility Act) | ||||||
|
|
||||||
| WCAG 2.1 has three levels of conformance: A, AA, and AAA. | ||||||
| Level AA exceeds the basic criteria for accessibility and is a common target for most organizations, so this is what we aim to support. | ||||||
|
Check warning on line 33 in docs/data/charts/accessibility/accessibility.md
|
||||||
alexfauquette marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
|
|
||||||
| The WAI-ARIA Authoring Practices includes examples on [Tooltip](https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/). | ||||||
|
|
||||||
| <!-- ### Dialog considerations | ||||||
| Both `Desktop` and `Mobile` Date and Time Pickers are using `role="dialog"` to display their interactive view parts and thus they should follow [Modal accessibility guidelines](/material-ui/react-modal/#accessibility). | ||||||
| This behavior is automated as much as possible, ensuring that the Date and Time Pickers are accessible in most cases. | ||||||
| A correct `aria-labelledby` value is assigned to the dialog component based on the following rules: | ||||||
| - Use `toolbar` id if the toolbar is visible; | ||||||
| - Use the id of the input label if the toolbar is hidden; | ||||||
| :::info | ||||||
| Make sure to provide an `aria-labelledby` prop to `popper` and/or `mobilePaper` slots in case you are using Date and Time Pickers component with **hidden toolbar** and **without a label**. | ||||||
| ::: --> | ||||||
JCQuintas marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
alexfauquette marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
|
|
||||||
| ## Animation | ||||||
|
|
||||||
| Most of the charts have an animation when rendering or when data update. | ||||||
alexfauquette marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| For users with vestibular motion disorders those animations can be problematic. | ||||||
| By default we skip animation based on the [`prefers-reduced-motion`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion) media feature. | ||||||
|
Check warning on line 54 in docs/data/charts/accessibility/accessibility.md
|
||||||
alexfauquette marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
|
|
||||||
| <!-- | ||||||
| ## Screen reader compatibility | ||||||
| Date and Time Pickers use ARIA roles and robust focus management across the interactive elements to convey the necessary information to users, being optimized for use with assistive technologies. | ||||||
| --> | ||||||
|
|
||||||
| ## Keyboard support | ||||||
|
|
||||||
| Set `enableKeyboardNavigation` to `true` to enable the keyboard navigation on your charts. | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we have a global enable/disable toggle for this? 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added a sentence about how to use theme provider to do so There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we add a demo? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done 👍 |
||||||
| This feature is currently supported by line, bar, pie, and scatter charts. | ||||||
|
|
||||||
| This makes the SVG component focusable thanks to [`tabIndex`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/tabindex). | ||||||
| When focused, the charts highlight a value item that can be modified with arrow navigation. | ||||||
|
||||||
| When focused, the charts highlight a value item that can be modified with arrow navigation. | |
| When focused, the chart highlights a value item that can be modified with arrow navigation. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import * as React from 'react'; | ||
| import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; | ||
| import * as pageProps from 'docsx/data/charts/accessibility/accessibility.md?muiMarkdown'; | ||
|
|
||
| export default function Page() { | ||
| return <MarkdownDocs {...pageProps} />; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,7 @@ import { BarElementOwnerState, useUtilityClasses } from './barElementClasses'; | |
| import { useInteractionItemProps } from '../hooks/useInteractionItemProps'; | ||
| import { useItemHighlighted } from '../hooks/useItemHighlighted'; | ||
| import { AnimatedBarElement, BarProps } from './AnimatedBarElement'; | ||
| import { useIsItemFocused } from '../hooks/useIsItemFocused'; | ||
|
|
||
| export interface BarElementSlots { | ||
| /** | ||
|
|
@@ -67,6 +68,11 @@ function BarElement(props: BarElementProps) { | |
| seriesId: id, | ||
| dataIndex, | ||
| }); | ||
| const isFocused = useIsItemFocused({ | ||
| seriesType: 'bar', | ||
| seriesId: id, | ||
| dataIndex, | ||
| }); | ||
|
|
||
| const ownerState = { | ||
| id, | ||
|
|
@@ -75,6 +81,7 @@ function BarElement(props: BarElementProps) { | |
| color, | ||
| isFaded, | ||
| isHighlighted, | ||
| isFocused, | ||
| }; | ||
|
|
||
| const classes = useUtilityClasses(ownerState); | ||
|
|
@@ -103,6 +110,7 @@ function BarElement(props: BarElementProps) { | |
| fill: color, | ||
| skipAnimation, | ||
| layout, | ||
| 'data-focused': isFocused || undefined, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Base UI uses
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| }, | ||
| className: classes.root, | ||
| ownerState, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| 'use client'; | ||
| import * as React from 'react'; | ||
| import { useTheme } from '@mui/material/styles'; | ||
| import { useFocusedItem } from '../hooks/useFocusedItem'; | ||
| import { useLineSeriesContext, useXAxes, useYAxes } from '../hooks'; | ||
|
|
||
| const RADIUS = 6; | ||
| export function FocusedMark() { | ||
| const theme = useTheme(); | ||
| const focusedItem = useFocusedItem(); | ||
|
|
||
| const lineSeries = useLineSeriesContext(); | ||
| const { xAxis, xAxisIds } = useXAxes(); | ||
| const { yAxis, yAxisIds } = useYAxes(); | ||
|
|
||
| if (focusedItem === null || focusedItem.seriesType !== 'line' || !lineSeries) { | ||
| return null; | ||
| } | ||
|
|
||
| const series = lineSeries?.series[focusedItem.seriesId]; | ||
|
|
||
| const xAxisId = series.xAxisId ?? xAxisIds[0]; | ||
| const yAxisId = series.yAxisId ?? yAxisIds[0]; | ||
|
|
||
| return ( | ||
| <rect | ||
| fill="none" | ||
| stroke={(theme.vars ?? theme).palette.text.primary} | ||
| strokeWidth={2} | ||
| x={xAxis[xAxisId].scale(xAxis[xAxisId].data![focusedItem.dataIndex])! - RADIUS} | ||
| y={yAxis[yAxisId].scale(series.stackedData[focusedItem.dataIndex][1])! - RADIUS} | ||
| width={2 * RADIUS} | ||
| height={2 * RADIUS} | ||
JCQuintas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| rx={3} | ||
| ry={3} | ||
| /> | ||
| ); | ||
| } | ||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.