react-compare-slider icon indicating copy to clipboard operation
react-compare-slider copied to clipboard

A11y support

Open acromatica opened this issue 3 years ago • 6 comments

Hello. Are you planning to add accessibility support (keyboard navigation and aria attributes for screen readers)? Right now it's impossible to move the handle using the keyboard, and there is no way to know current position of the handle if you're using a screen reader. Also as the items are rendered in reverse order (item 2 - item 1) if you're using a screen reader it will read the content in a reverse order as well (first the content of the right block and then the content of the left block).

acromatica avatar Feb 21 '22 14:02 acromatica

Hi @acromatica, thanks looking into the accessibility issues!

I've been meaning to resolve the attributes for a while but wasn't able to settle on a good solution. Do you know which attributes would be best for the position, and if there's a way to relate the position to the two items?

The keyboard navigation should be easy enough to add (there was a previous discussion where this was implemented with custom event bindings). I think there would also need to be a new prop to set how much to increment the position by on key press too.

The ordering of the items should be fairly trivial to resolve, I think they could be switched in the render and reordered using CSS order as its only presentational.

I'll start looking into some solutions, let me know if you have any suggestions :)

nerdyman avatar Feb 21 '22 21:02 nerdyman

Hi Ricky, for sure! The interactions of this slider are very similar to a range selector, so you should look into ARIA slider role: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/slider_role

The attributes you need to add to the handle element:

  • tabindex="0": this way you'll be able to use it from the keyboard;
  • role="slider": screen readers will prompt the users to interact with it as with a range selector;
  • aria-valuemin="0": min value;
  • aria-valuemax="100": max value;
  • aria-valuenow="50": current value, it should update every time the position of the handle changes;
  • aria-valuetext="...": here goes the text that describes what's in the slider. I'd suggest something like "50% of [item 1 description] shown/revealed next to [item 2 description]". In case of images you could use alt texts for the descriptions, but I think it should be a new prop so it's possible to add the text that better describes the purpose of item 1 and item 2. 50% bit should update as the position of the handle changes.

Alternatively, instead of aria-valuetext, you could use a liveregion that would describe what's happening in the slider. For example, something like this: <span class="liveregion" aria-live="polite">50 Percent of [item 1 description] revealed next to [item 2 description]</span> If you choose this approach you should to add some kind of delay between the last update of the handle's position and the update of the text inside of the liveregion, because screen readers will read the text each time it changes. So if a user is pressing an arrow key repeatedly, multiple times per second, it's better to wait till they stop and only after that update the text, so they don't hear the text from the liveregion while they're still updating the position of the handle. Liveregion should be hidden visually and from the screen readers unless the handle is focused (we don't want screen readers to read this text randomly when users don't interact with the slider), so css should be something like:

.liveregion {
	display: none !important; /* Hide visually and from the screen readers */
	border: 0 !important;
	clip: rect(1px, 1px, 1px, 1px) !important;
	-webkit-clip-path: inset(50%) !important;
		clip-path: inset(50%) !important;
	height: 1px !important;
	margin: -1px !important;
	overflow: hidden !important;
	padding: 0 !important;
	position: absolute !important;
	width: 1px !important;
	white-space: nowrap !important;
}

.handle:focus ~ .liveregion {
	display: block !important; /* Will be "visible" only for the screen readers, but still hidden visually */
}

Re the ordering of the items, css order is a great idea 👍 Screen readers will ignore css order and will read the content in the order it appears in the markup.

Hope this makes sense, feel free to ping me if you have any questions :)

acromatica avatar Feb 22 '22 12:02 acromatica

That's awesome @acromatica, thanks for the detailed info 🙌 I'll start adding the features this week.

nerdyman avatar Feb 22 '22 14:02 nerdyman

Any update?

mbcod3 avatar Aug 16 '22 19:08 mbcod3

No progress yet @mbcod3. I'll hopefully get sorted in the next month or so.

nerdyman avatar Aug 24 '22 10:08 nerdyman

Hey @acromatica, I finally got around to implementing this, there's some testing and minor issues to resolve in Safari (keyboard nav back and forth doesn't move consistently) before releasing but feel free to preview it at https://react-compare-slider-git-feature-a11y-support-nerdyman.vercel.app/

nerdyman avatar Oct 01 '22 17:10 nerdyman

This has been released in v3!

npm install react-compare-slider@latest
yarn add react-compare-slider@latest
pnpm install react-compare-slider@latest

nerdyman avatar Oct 29 '23 17:10 nerdyman