Skip to content

Accessibility audit fixes for Radio Group, Slider, SplitView, Spinner, Toast #2337

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

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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions components/component-docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -14124,13 +14124,17 @@
"label": {
"name": "string",
"required": false
},
"required": {
"name": "string",
"required": false
}
}
},
"required": false,
"description": "**Assistive text for accessibility**\n* `label`: This label appears in the legend.",
"description": "**Assistive text for accessibility**\n* `label`: This label appears in the legend.\n* `required`: Text to help identify the group as required",
"defaultValue": {
"value": "{}",
"value": "{ required: 'Required' }",
"computed": false
}
},
Expand Down Expand Up @@ -14898,14 +14902,22 @@
"type": {
"name": "shape",
"value": {
"disabled": {
"name": "string",
"required": false
},
"label": {
"name": "string",
"required": false
}
}
},
"required": false,
"description": "Assistive text for accessibility**\n`label`: Visually hidden label but read out loud by screen readers."
"description": "Assistive text for accessibility**\n`disabled`: Read by screen readers to indicate a disabled slider\n`label`: Visually hidden label but read out loud by screen readers.",
"defaultValue": {
"value": "{ disabled: 'Disabled' }",
"computed": false
}
},
"classNameContainer": {
"type": {
Expand Down Expand Up @@ -16612,9 +16624,9 @@
}
},
"required": false,
"description": "**Assistive text for accessibility**\nThis object is merged with the default props object on every render.\n* `closeButton`: This is a visually hidden label for the close button.\n_Tested with snapshot testing._",
"description": "**Assistive text for accessibility**\nThis object is merged with the default props object on every render.\n* `closeButton`: This is a visually hidden label for the close button.\n* `error`: This is a visually hidden label to mark the toast as an error variant\n* `info`: This is a visually hidden label to mark the toast as an info variant\n* `success`: This is a visually hidden label to mark the toast as an success variant\n* `warning`: This is a visually hidden label to mark the toast as an warning variant\n_Tested with snapshot testing._",
"defaultValue": {
"value": "{\n closeButton: 'Close',\n}",
"value": "{\n closeButton: 'Close',\n error: 'error',\n info: 'info',\n success: 'success',\n warning: 'warning',\n}",
"computed": false
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,12 @@ exports[`DOM snapshots SLDSRadioButtonGroup Required 1`] = `
title="required"
>
*
<div
className="slds-assistive-text"
>
Required

</div>
</abbr>
Day of week
</legend>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ describe('RadioButtonGroup', function() {
attachTo: mountNode,
});
const abbr = wrapper.find('abbr');
expect(abbr.text()).to.equal('*', 'there is a required indicator');
expect(abbr.text()).to.equal('*Required ', 'there is a required indicator');
});

it('triggers a change callback', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,12 @@ exports[`DOM snapshots SLDSRadioGroup Required 1`] = `
title="required"
>
*
<div
className="slds-assistive-text"
>
Required

</div>
</abbr>
Radio Group Label
</legend>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ describe('RadioGroup', function() {
it('renders a required indicator', () => {
wrapper = mount(<RadioGroupExample required />, { attachTo: mountNode });
const abbr = wrapper.find('abbr');
expect(abbr.text()).to.equal('*', 'there is a required indicator');
expect(abbr.text()).to.equal('*Required ', 'there is a required indicator');
});

it('triggers a change callback', () => {
Expand Down
21 changes: 16 additions & 5 deletions components/radio-group/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ const propTypes = {
/**
* **Assistive text for accessibility**
* * `label`: This label appears in the legend.
* * `required`: Text to help identify the group as required
*/
assistiveText: PropTypes.shape({
label: PropTypes.string,
required: PropTypes.string,
}),
/**
* Children are expected to be Radio components.
Expand Down Expand Up @@ -69,7 +71,11 @@ const propTypes = {
variant: PropTypes.oneOf(['base', 'button-group']),
};

const defaultProps = { assistiveText: {}, labels: {}, variant: 'base' };
const defaultProps = {
assistiveText: { required: 'Required' },
labels: {},
variant: 'base',
};

/**
* A styled select list that can have a single entry checked at any one time.
Expand Down Expand Up @@ -104,6 +110,10 @@ class RadioGroup extends React.Component {
? assign({}, defaultProps.labels, this.props.labels)
: defaultProps.labels;

const assistiveText = {
...defaultProps.assistiveText,
...this.props.assistiveText,
};
const children = React.Children.map(this.props.children, (child) =>
React.cloneElement(child, {
name: this.getName(),
Expand All @@ -123,17 +133,18 @@ class RadioGroup extends React.Component {
className={classNames(
'slds-form-element__legend',
'slds-form-element__label',
this.props.assistiveText.label ? 'slds-assistive-text' : ''
assistiveText.label ? 'slds-assistive-text' : ''
)}
>
{this.props.required ? (
<abbr className="slds-required" title="required">
{'*'}
<div className="slds-assistive-text">
{assistiveText.required}{' '}
</div>
</abbr>
) : null}
{this.props.assistiveText.label
? this.props.assistiveText.label
: this.labels.label}
{assistiveText.label ? assistiveText.label : this.labels.label}
</legend>
<div
className={classNames(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ exports[`DOM snapshots SLDSSlider Disabled 1`] = `
-
100
</span>
<span
className="slds-assistive-text"
>

Disabled
</span>
</span>
</label>
<div
Expand Down
14 changes: 13 additions & 1 deletion components/slider/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ const propTypes = {
'aria-describedby': PropTypes.string,
/**
* Assistive text for accessibility**
* `disabled`: Read by screen readers to indicate a disabled slider
* `label`: Visually hidden label but read out loud by screen readers.
*
*/
assistiveText: PropTypes.shape({
disabled: PropTypes.string,
label: PropTypes.string,
}),
/**
Expand Down Expand Up @@ -108,6 +109,7 @@ const propTypes = {
};

const defaultProps = {
assistiveText: { disabled: 'Disabled' },
min: 0,
max: 100,
step: 1,
Expand Down Expand Up @@ -157,6 +159,10 @@ class Slider extends React.Component {
const ariaProps = getAriaProps(this.props);
ariaProps['aria-describedby'] = this.getErrorId();

const assistiveText = {
...defaultProps.assistiveText,
...this.props.assistiveText,
};
const labelText =
this.props.label ||
(this.props.assistiveText && this.props.assistiveText.label);
Expand Down Expand Up @@ -187,6 +193,12 @@ class Slider extends React.Component {
{' - '}
{this.props.max}
</span>
{this.props.disabled ? (
<span className="slds-assistive-text">
{' '}
{assistiveText.disabled}
</span>
) : null}
</span>
</label>
<div className="slds-form-element__control">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ exports[`DOM snapshots SLDSSpinner Docs site Default 1`] = `
<span
className="slds-assistive-text"
>
Small spinner
Main Frame Loading...
</span>
<div
className="slds-spinner__dot-a"
Expand Down Expand Up @@ -337,7 +337,7 @@ exports[`DOM snapshots SLDSSpinner Small 1`] = `
<span
className="slds-assistive-text"
>
Small spinner
Main Frame Loading...
</span>
<div
className="slds-spinner__dot-a"
Expand Down
2 changes: 1 addition & 1 deletion components/spinner/__docs__/storybook-stories.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ storiesOf(SPINNER, module)
size: 'small',
variant: 'base',
assistiveText: {
label: 'Small spinner',
label: 'Main Frame Loading...',
},
})
)
Expand Down
2 changes: 1 addition & 1 deletion components/spinner/__examples__/default.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class Example extends React.Component {
<Spinner
size="small"
variant="base"
assistiveText={{ label: 'Small spinner' }}
assistiveText={{ label: 'Main Frame Loading...' }}
/>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ exports[`DOM snapshots SLDSSplitView Base: Multiple 1`] = `
className="slds-grid slds-grid_vertical slds-scrollable_none"
>
<a
aria-live="polite"
className="slds-split-view__list-header slds-grid slds-text-link_reset"
href="javascript:void(0);"
onClick={[Function]}
Expand All @@ -421,7 +422,9 @@ exports[`DOM snapshots SLDSSplitView Base: Multiple 1`] = `
}
}
>
<span>
<span
aria-sort="Descending"
>
<span
className="slds-assistive-text"
>
Expand Down Expand Up @@ -1265,6 +1268,7 @@ exports[`DOM snapshots SLDSSplitView Base: Open 1`] = `
className="slds-grid slds-grid_vertical slds-scrollable_none"
>
<a
aria-live="polite"
className="slds-split-view__list-header slds-grid slds-text-link_reset"
href="javascript:void(0);"
onClick={[Function]}
Expand All @@ -1275,7 +1279,9 @@ exports[`DOM snapshots SLDSSplitView Base: Open 1`] = `
}
}
>
<span>
<span
aria-sort="Descending"
>
<span
className="slds-assistive-text"
>
Expand Down Expand Up @@ -2118,6 +2124,7 @@ exports[`DOM snapshots SLDSSplitView Custom List 1`] = `
className="slds-grid slds-grid_vertical slds-scrollable_none"
>
<a
aria-live="polite"
className="slds-split-view__list-header slds-grid slds-text-link_reset"
href="javascript:void(0);"
onClick={[Function]}
Expand All @@ -2128,7 +2135,9 @@ exports[`DOM snapshots SLDSSplitView Custom List 1`] = `
}
}
>
<span>
<span
aria-sort="Descending"
>
<span
className="slds-assistive-text"
>
Expand Down Expand Up @@ -2735,6 +2744,7 @@ exports[`DOM snapshots SLDSSplitView External State 1`] = `
className="slds-grid slds-grid_vertical slds-scrollable_none"
>
<a
aria-live="polite"
className="slds-split-view__list-header slds-grid slds-text-link_reset"
href="javascript:void(0);"
onClick={[Function]}
Expand All @@ -2745,7 +2755,9 @@ exports[`DOM snapshots SLDSSplitView External State 1`] = `
}
}
>
<span>
<span
aria-sort="Descending"
>
<span
className="slds-assistive-text"
>
Expand Down
9 changes: 8 additions & 1 deletion components/split-view/listbox.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ class SplitViewListbox extends React.Component {
headerWrapper(children) {
return this.props.events.onSort ? (
<a
aria-live="polite"
style={{ borderTop: '0' }}
href="javascript:void(0);" // eslint-disable-line no-script-url
role="button"
Expand All @@ -316,7 +317,13 @@ class SplitViewListbox extends React.Component {
header() {
return this.props.labels.header
? this.headerWrapper(
<span>
<span
aria-sort={
this.props.sortDirection === SORT_OPTIONS.DOWN
? this.props.assistiveText.sort.descending
: this.props.assistiveText.sort.ascending
}
>
<span className="slds-assistive-text">
{this.props.assistiveText.sort.sortedBy}
{': '}
Expand Down
2 changes: 1 addition & 1 deletion components/toast/__examples__/duration-toast.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class Example extends React.Component {
<ToastContainer>
{this.state.isOpen ? (
<Toast
duration={1000}
duration={10000}
labels={{
heading: '26 potential duplicate leads were found.',
headingLink: 'Select Leads to Merge',
Expand Down
16 changes: 12 additions & 4 deletions components/toast/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ const propTypes = {
* **Assistive text for accessibility**
* This object is merged with the default props object on every render.
* * `closeButton`: This is a visually hidden label for the close button.
* * `error`: This is a visually hidden label to mark the toast as an error variant
* * `info`: This is a visually hidden label to mark the toast as an info variant
* * `success`: This is a visually hidden label to mark the toast as an success variant
* * `warning`: This is a visually hidden label to mark the toast as an warning variant
* _Tested with snapshot testing._
*/
assistiveText: PropTypes.shape({
Expand Down Expand Up @@ -86,6 +90,10 @@ const propTypes = {
const defaultProps = {
assistiveText: {
closeButton: 'Close',
error: 'error',
info: 'info',
success: 'success',
warning: 'warning',
},
variant: 'info',
};
Expand Down Expand Up @@ -156,10 +164,10 @@ class Toast extends React.Component {
const heading = labels.heading || this.props.content; // eslint-disable-line react/prop-types

const assistiveTextVariant = {
info: 'info',
success: 'success',
warning: 'warning',
error: 'error',
info: assistiveText.info,
success: assistiveText.success,
warning: assistiveText.warning,
error: assistiveText.error,
};

const defaultIcons = {
Expand Down