Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
3 changes: 3 additions & 0 deletions changelogs/upcoming/7675.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
**Accessibility**

- Added `aria-valuenow` and `aria-valuetext` attributes to `EuiRange` for improved screen reader UX
Comment thread
1Copenut marked this conversation as resolved.
Outdated
10 changes: 5 additions & 5 deletions src-docs/src/views/range/levels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ export default () => {
];

const customTicks = [
{ label: 'low', value: 0 },
{ label: 'intermediate', value: 15 },
{ label: 'moderate', value: 35 },
{ label: 'high', value: 65 },
{ label: 'severe', value: 85 },
{ label: 'low', value: 0, accessibleLabel: 'low' },
Comment thread
1Copenut marked this conversation as resolved.
Outdated
{ label: 'intermediate', value: 15, accessibleLabel: 'intermediate' },
{ label: 'moderate', value: 35, accessibleLabel: 'moderate' },
{ label: 'high', value: 65, accessibleLabel: 'high' },
{ label: 'severe', value: 85, accessibleLabel: 'severe' },
];

const customColorsLevels = [
Expand Down
10 changes: 10 additions & 0 deletions src-docs/src/views/range/range_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,16 @@ export const RangeControlExample = {
<EuiCode>label</EuiCode>. The value must be included in the range of
values (min-max), though the label may be anything you choose.
</p>
<p>
The <EuiCode>EuiRangeTick</EuiCode> interface now includes an
optional <EuiCode>accessibleLabel</EuiCode>. This property is
combined with the current <EuiCode>value</EuiCode> to render an{' '}
<EuiCode>aria-valuetext</EuiCode> attribute. If the accessible label
is not included, <EuiCode>aria-valuetext</EuiCode> will be the
computed current value. This attribute is announced to screen reader
users and is useful when values are defined differently than tick
labels.
</p>
Comment thread
1Copenut marked this conversation as resolved.
<EuiCallOut
color="warning"
title="Minimum of 5px width per tick allowed"
Expand Down
16 changes: 8 additions & 8 deletions src-docs/src/views/range/ticks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,15 @@ export default () => {
min={0}
max={84}
ticks={[
{ label: '1 GB', value: 0 },
{ label: '2GB', value: 14 },
{ label: '4GB', value: 28 },
{ label: '8GB', value: 42 },
{ label: '16GB', value: 56 },
{ label: '32GB', value: 70 },
{ label: '64GB', value: 84 },
{ label: '1 GB', value: 0, accessibleLabel: 'one gigabyte' },
{ label: '2GB', value: 14, accessibleLabel: 'two gigabytes' },
{ label: '4GB', value: 28, accessibleLabel: 'four gigabytes' },
{ label: '8GB', value: 42, accessibleLabel: 'eight gigabytes' },
{ label: '16GB', value: 56, accessibleLabel: 'sixteen gigabytes' },
{ label: '32GB', value: 70, accessibleLabel: 'thirty-two gigabytes' },
{ label: '64GB', value: 84, accessibleLabel: 'sixty-four gigabytes' },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😍 Now this is an example that makes sense to me! Huzzah!

]}
aria-label="An example of EuiDualRange with no linear intervals"
aria-label="An example of EuiRange with no linear intervals"
/>
</>
);
Expand Down
119 changes: 119 additions & 0 deletions src/components/form/range/__snapshots__/range.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ exports[`EuiRange allows value prop to accept a number 1`] = `
>
<input
aria-hidden="false"
aria-valuenow="8"
class="euiRangeSlider emotion-euiRangeSlider"
id="generated-id"
max="100"
Expand Down Expand Up @@ -67,6 +68,7 @@ exports[`EuiRange inherits fullWidth from <EuiForm /> 1`] = `
>
<input
aria-hidden="false"
aria-valuenow="20"
class="euiRangeSlider emotion-euiRangeSlider"
id="generated-id"
max="100"
Expand All @@ -91,6 +93,7 @@ exports[`EuiRange is rendered 1`] = `
<input
aria-hidden="false"
aria-label="aria-label"
aria-valuenow="8"
class="euiRangeSlider emotion-euiRangeSlider"
data-test-subj="test subject string"
id="id"
Expand All @@ -115,6 +118,7 @@ exports[`EuiRange props compressed should render 1`] = `
>
<input
aria-hidden="false"
aria-valuenow="8"
class="euiRangeSlider emotion-euiRangeSlider"
id="generated-id"
max="100"
Expand Down Expand Up @@ -166,6 +170,7 @@ exports[`EuiRange props custom ticks should render 1`] = `
</div>
<input
aria-hidden="false"
aria-valuenow="8"
class="euiRangeSlider emotion-euiRangeSlider-hasTicks"
id="generated-id"
max="100"
Expand All @@ -188,6 +193,7 @@ exports[`EuiRange props disabled should render 1`] = `
>
<input
aria-hidden="false"
aria-valuenow="8"
class="euiRangeSlider emotion-euiRangeSlider"
disabled=""
id="generated-id"
Expand All @@ -211,6 +217,7 @@ exports[`EuiRange props fullWidth should render 1`] = `
>
<input
aria-hidden="false"
aria-valuenow="8"
class="euiRangeSlider emotion-euiRangeSlider"
id="generated-id"
max="100"
Expand All @@ -223,6 +230,111 @@ exports[`EuiRange props fullWidth should render 1`] = `
</div>
`;

exports[`EuiRange props input should include aria-valuetext when value equals tick[value] 1`] = `
<div
class="euiRangeWrapper euiRange emotion-euiRangeWrapper-regular-euiRange"
>
<div
aria-hidden="false"
class="euiRangeTrack emotion-euiRangeTrack-hasTicks"
>
<div
class="euiRangeTicks emotion-euiRangeTicks-regular-isCustom"
>
<button
class="euiRangeTick emotion-euiRangeTick-isCustom-hasPseudoTickMark-regular"
style="inset-inline-start: calc(-Infinity% + 8px);"
tabindex="-1"
title="20kb"
type="button"
value="20"
>
20kb
</button>
<button
class="euiRangeTick emotion-euiRangeTick-isCustom-isMax-regular"
style="inset-inline-end: 0%; margin-inline-end: -1.25em;"
tabindex="-1"
title="100kb"
type="button"
value="100"
>
<span
aria-hidden="true"
class="euiRangeTick__pseudo emotion-euiRangeTick__pseudo"
style="margin-inline-end: calc(1.25em + 4px);"
/>
100kb
</button>
</div>
<input
aria-hidden="false"
aria-valuenow="20"
aria-valuetext="20, (twenty kilobytes)"
class="euiRangeSlider emotion-euiRangeSlider-hasTicks"
id="generated-id"
max="100"
min="0"
step="1"
type="range"
value="20"
/>
</div>
</div>
`;

exports[`EuiRange props input should not include aria-valuetext when values are different 1`] = `
<div
class="euiRangeWrapper euiRange emotion-euiRangeWrapper-regular-euiRange"
>
<div
aria-hidden="false"
class="euiRangeTrack emotion-euiRangeTrack-hasTicks"
>
<div
class="euiRangeTicks emotion-euiRangeTicks-regular-isCustom"
>
<button
class="euiRangeTick emotion-euiRangeTick-isCustom-hasPseudoTickMark-regular"
style="inset-inline-start: calc(-Infinity% + 8px);"
tabindex="-1"
title="20kb"
type="button"
value="20"
>
20kb
</button>
<button
class="euiRangeTick emotion-euiRangeTick-isCustom-isMax-regular"
style="inset-inline-end: 0%; margin-inline-end: -1.25em;"
tabindex="-1"
title="100kb"
type="button"
value="100"
>
<span
aria-hidden="true"
class="euiRangeTick__pseudo emotion-euiRangeTick__pseudo"
style="margin-inline-end: calc(1.25em + 4px);"
/>
100kb
</button>
</div>
<input
aria-hidden="false"
aria-valuenow="8"
class="euiRangeSlider emotion-euiRangeSlider-hasTicks"
id="generated-id"
max="100"
min="0"
step="1"
type="range"
value="8"
/>
</div>
</div>
`;

exports[`EuiRange props input should render 1`] = `
<div
class="euiRangeWrapper euiRange testClass1 testClass2 emotion-euiRangeWrapper-regular-euiRange-hasInput-euiTestCss"
Expand All @@ -234,6 +346,7 @@ exports[`EuiRange props input should render 1`] = `
<input
aria-hidden="true"
aria-label="aria-label"
aria-valuenow="8"
class="euiRangeSlider emotion-euiRangeSlider"
data-test-subj="test subject string"
max="100"
Expand Down Expand Up @@ -287,6 +400,7 @@ exports[`EuiRange props labels should render 1`] = `
>
<input
aria-hidden="false"
aria-valuenow="8"
class="euiRangeSlider emotion-euiRangeSlider"
id="generated-id"
max="100"
Expand Down Expand Up @@ -326,6 +440,7 @@ exports[`EuiRange props levels should render 1`] = `
</div>
<input
aria-hidden="false"
aria-valuenow="20"
class="euiRangeSlider emotion-euiRangeSlider-thumb"
id="generated-id"
max="100"
Expand Down Expand Up @@ -385,6 +500,7 @@ exports[`EuiRange props range should render 1`] = `
>
<input
aria-hidden="false"
aria-valuenow="8"
class="euiRangeSlider emotion-euiRangeSlider-hasRange"
id="generated-id"
max="100"
Expand Down Expand Up @@ -480,6 +596,7 @@ exports[`EuiRange props slider should display in popover 1`] = `
<input
aria-hidden="true"
aria-label="aria-label"
aria-valuenow="8"
class="euiRangeSlider emotion-euiRangeSlider"
data-test-subj="test subject string"
max="100"
Expand Down Expand Up @@ -584,6 +701,7 @@ exports[`EuiRange props ticks should render 1`] = `
</div>
<input
aria-hidden="false"
aria-valuenow="8"
class="euiRangeSlider emotion-euiRangeSlider-hasTicks"
id="generated-id"
max="100"
Expand All @@ -606,6 +724,7 @@ exports[`EuiRange props value should render 1`] = `
>
<input
aria-hidden="false"
aria-valuenow="200"
class="euiRangeSlider emotion-euiRangeSlider"
id="generated-id"
max="100"
Expand Down
63 changes: 62 additions & 1 deletion src/components/form/range/range.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import React from 'react';
import { fireEvent } from '@testing-library/react';
import { fireEvent, getByRole } from '@testing-library/react';
Comment thread
cee-chen marked this conversation as resolved.
Outdated
import { shouldRenderCustomStyles } from '../../../test/internal';
import { requiredProps } from '../../../test/required_props';
import { render } from '../../../test/rtl';
Expand Down Expand Up @@ -143,6 +143,67 @@ describe('EuiRange', () => {
expect(container.firstChild).toMatchSnapshot();
});

test('input should include aria-valuetext when value equals tick[value]', () => {
const { container } = render(
<EuiRange
{...props}
showTicks
ticks={[
{
label: '20kb',
value: 20,
accessibleLabel: 'twenty kilobytes',
},
{
label: '100kb',
value: 100,
accessibleLabel: 'one-hundred kilobytes',
},
]}
value={20}
/>
);

const input = getByRole(container, 'slider');

expect(input).toBeInTheDocument();
expect(input.getAttribute('aria-valuenow')).toEqual('20');
expect(input.getAttribute('aria-valuetext')).toEqual(
'20, (twenty kilobytes)'
);

expect(container.firstChild).toMatchSnapshot();
});

test('input should not include aria-valuetext when values are different', () => {
const { container } = render(
<EuiRange
{...props}
showTicks
ticks={[
{
label: '20kb',
value: 20,
accessibleLabel: 'twenty kilobytes',
},
{
label: '100kb',
value: 100,
accessibleLabel: 'one-hundred kilobytes',
},
]}
/>
);

const input = getByRole(container, 'slider');

expect(input).toBeInTheDocument();
expect(input.getAttribute('aria-valuenow')).toEqual('8');
expect(input.getAttribute('aria-valuetext')).toBeFalsy();

expect(container.firstChild).toMatchSnapshot();
});

test('slider should display in popover', () => {
const { container, baseElement, getByTestSubject } = render(
<EuiRange
Expand Down
Loading