-
Notifications
You must be signed in to change notification settings - Fork 121
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): add label for screen readers #1121
Changes from 1 commit
1087852
4cb8ddc
e1c4fcd
e20033a
2612a2a
a88737d
19fb650
d9f34a7
532bd0d
356b754
e770e99
c1a9b8d
6150d2d
b81e6f8
d757d9e
deff638
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 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -79,11 +79,11 @@ export interface ReactiveChartStateProps { | |||||||||||||
annotationSpecs: AnnotationSpec[]; | ||||||||||||||
panelGeoms: PanelGeoms; | ||||||||||||||
seriesTypes: Set<SeriesType>; | ||||||||||||||
description?: string; | ||||||||||||||
accessibilityDescription?: string; | ||||||||||||||
useDefaultSummary: boolean; | ||||||||||||||
chartId: string; | ||||||||||||||
label?: string; | ||||||||||||||
labelledBy?: string; | ||||||||||||||
ariaLabel?: string; | ||||||||||||||
ariaLabelledBy?: string; | ||||||||||||||
HeadingLevel: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p'; | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
|
@@ -95,6 +95,10 @@ interface ReactiveChartOwnProps { | |||||||||||||
} | ||||||||||||||
const CLIPPING_MARGINS = 0.5; | ||||||||||||||
|
||||||||||||||
type AriaProps = { | ||||||||||||||
[key: string]: string | undefined; | ||||||||||||||
}; | ||||||||||||||
|
||||||||||||||
type XYChartProps = ReactiveChartStateProps & ReactiveChartDispatchProps & ReactiveChartOwnProps; | ||||||||||||||
class XYChartComponent extends React.Component<XYChartProps> { | ||||||||||||||
static displayName = 'XYChart'; | ||||||||||||||
|
@@ -162,11 +166,11 @@ class XYChartComponent extends React.Component<XYChartProps> { | |||||||||||||
isChartEmpty, | ||||||||||||||
chartContainerDimensions: { width, height }, | ||||||||||||||
seriesTypes, | ||||||||||||||
description, | ||||||||||||||
accessibilityDescription, | ||||||||||||||
useDefaultSummary, | ||||||||||||||
chartId, | ||||||||||||||
label, | ||||||||||||||
labelledBy, | ||||||||||||||
ariaLabel, | ||||||||||||||
ariaLabelledBy, | ||||||||||||||
HeadingLevel, | ||||||||||||||
} = this.props; | ||||||||||||||
|
||||||||||||||
|
@@ -178,12 +182,16 @@ class XYChartComponent extends React.Component<XYChartProps> { | |||||||||||||
const chartSeriesTypes = | ||||||||||||||
seriesTypes.size > 1 ? `Mixed chart: ${[...seriesTypes].join(' and ')} chart` : `${[...seriesTypes]} chart`; | ||||||||||||||
const chartIdDescription = `${chartId}--description`; | ||||||||||||||
const chartIdLabel = label ? `${chartId}--label` : undefined; | ||||||||||||||
const chartIdLabel = ariaLabel ? `${chartId}--label` : undefined; | ||||||||||||||
|
||||||||||||||
const ariaProps = { | ||||||||||||||
'aria-labelledby': labelledBy || label ? labelledBy ?? chartIdLabel : '', | ||||||||||||||
'aria-describedby': `${labelledBy || ''} ${useDefaultSummary ? chartIdLabel : ''}`, | ||||||||||||||
}; | ||||||||||||||
const ariaProps: AriaProps = {}; | ||||||||||||||
|
||||||||||||||
if (ariaLabelledBy || ariaLabel) { | ||||||||||||||
ariaProps['aria-labelledby'] = ariaLabelledBy ?? chartIdLabel; | ||||||||||||||
} | ||||||||||||||
if (ariaLabelledBy || useDefaultSummary) { | ||||||||||||||
ariaProps['aria-describedby'] = `${ariaLabelledBy || ''} ${useDefaultSummary ? chartIdLabel : 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. @markov00 Good catch in #1121 (comment) Adding a suggestion here so I could target more lines, I think the
Suggested change
(I'm suggesting making a new id just for the @rshen91 Feel free to reach out if this suggestion doesn't make any sense! It's a little convoluted. 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. Woops added this in 6150d2d thank you! |
||||||||||||||
return ( | ||||||||||||||
<figure {...ariaProps}> | ||||||||||||||
<canvas | ||||||||||||||
|
@@ -198,10 +206,10 @@ class XYChartComponent extends React.Component<XYChartProps> { | |||||||||||||
// eslint-disable-next-line jsx-a11y/no-interactive-element-to-noninteractive-role | ||||||||||||||
role="presentation" | ||||||||||||||
> | ||||||||||||||
{label && <HeadingLevel id={chartIdLabel}>{label}</HeadingLevel>} | ||||||||||||||
{(description || useDefaultSummary) && ( | ||||||||||||||
{ariaLabel && <HeadingLevel id={chartIdLabel}>{ariaLabel}</HeadingLevel>} | ||||||||||||||
{(accessibilityDescription || useDefaultSummary) && ( | ||||||||||||||
<div className="echScreenReaderOnly"> | ||||||||||||||
{description && <p id={chartIdDescription}>{description}</p>} | ||||||||||||||
{accessibilityDescription && <p id={chartIdDescription}>{accessibilityDescription}</p>} | ||||||||||||||
{useDefaultSummary && ( | ||||||||||||||
<dl> | ||||||||||||||
<dt>Chart type</dt> | ||||||||||||||
|
@@ -264,11 +272,11 @@ const DEFAULT_PROPS: ReactiveChartStateProps = { | |||||||||||||
annotationSpecs: [], | ||||||||||||||
panelGeoms: [], | ||||||||||||||
seriesTypes: new Set(), | ||||||||||||||
description: undefined, | ||||||||||||||
accessibilityDescription: undefined, | ||||||||||||||
useDefaultSummary: true, | ||||||||||||||
chartId: '', | ||||||||||||||
label: undefined, | ||||||||||||||
labelledBy: undefined, | ||||||||||||||
ariaLabel: undefined, | ||||||||||||||
ariaLabelledBy: undefined, | ||||||||||||||
HeadingLevel: 'h2', | ||||||||||||||
}; | ||||||||||||||
|
||||||||||||||
|
@@ -278,7 +286,14 @@ const mapStateToProps = (state: GlobalChartState): ReactiveChartStateProps => { | |||||||||||||
} | ||||||||||||||
|
||||||||||||||
const { geometries, geometriesIndex } = computeSeriesGeometriesSelector(state); | ||||||||||||||
const { debug, description, useDefaultSummary, label, labelledBy, HeadingLevel } = getSettingsSpecSelector(state); | ||||||||||||||
const { | ||||||||||||||
debug, | ||||||||||||||
accessibilityDescription, | ||||||||||||||
useDefaultSummary, | ||||||||||||||
ariaLabel, | ||||||||||||||
ariaLabelledBy, | ||||||||||||||
HeadingLevel, | ||||||||||||||
} = getSettingsSpecSelector(state); | ||||||||||||||
|
||||||||||||||
return { | ||||||||||||||
initialized: true, | ||||||||||||||
|
@@ -300,11 +315,11 @@ const mapStateToProps = (state: GlobalChartState): ReactiveChartStateProps => { | |||||||||||||
annotationSpecs: getAnnotationSpecsSelector(state), | ||||||||||||||
panelGeoms: computePanelsSelectors(state), | ||||||||||||||
seriesTypes: getSeriesTypes(state), | ||||||||||||||
description, | ||||||||||||||
accessibilityDescription, | ||||||||||||||
useDefaultSummary, | ||||||||||||||
chartId: getChartIdSelector(state), | ||||||||||||||
label, | ||||||||||||||
labelledBy, | ||||||||||||||
ariaLabel, | ||||||||||||||
ariaLabelledBy, | ||||||||||||||
HeadingLevel, | ||||||||||||||
}; | ||||||||||||||
}; | ||||||||||||||
|
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.
each prop name should follow the
camelCase
with the first char lowercase, independently if you use them later as componentThere 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.
We should also sanitize this: it's true that in a TS this will throw error if the value is one of the union type, but in the JS compiled world not. This can lead to errors if this heading comes from an user input, or stored string value.
we can have a function that checks and returns/construct the appropriate header based on the input, like:
@nickofthyme other suggestions?