joelmturner pyramid logo

About

Blog

Illustration

TIL

Uses

About

Blog

Illustration

TIL

Uses

Beginning Web Accessibility in React

Table of Contents

Linting Rules for a11y

One of the best ways to get some useful suggestions is to add the plugin, eslint-plugin-jsx-a11y to your project. After I got it installed my editor lit up like New York City at night. Whew, I had some work to do.

WAI-ARIA

WAI-ARIA is explained well from MDN:

The three main features are Roles, Properties, and States.

Roles

It's best to use semantic elements for desired actions. A good example is to use the button element for a user action. If we are using a different element to perform the role of a button we can use a role to help out. An example might be an svg icon with an onClick method.

<svg viewBox="0 0 128 128" onClick="{myOnClickFn}" role="button">
<path d="M 10 10 H 90 V 90 H 10 L 10 10" />
</svg>

Having a role of button tells the screen reader that the intention of this icon is to be a button.

Here's a list from MDN of all the ARIA roles.

Properties

Properties let us give an element extra meaning if needed. A common example is in a form input. We may have a visual indicator to show that an input is required. Now we can add a data attribute of aria-required="true" to let the user know that the input needs to be valid.

<form onSubmit="{onSubmit}">
<label for="fieldName">Name</label>
<input name="fieldName" type="text" />
<label for="fieldEmail">Email</label>
<input name="fieldEmail" type="email" aria-required="true" />
</form>

States

This is much like states in javascript. We may have a disabled input that will become enabled after validation of a previous field. We can specify the disabled state with aria-disabled="true".

<form onSubmit="{onSubmit}">
<label for="fieldName">Name</label>
<input name="fieldName" type="text" />
<label for="fieldEmail">Email</label>
<input name="fieldEmail" type="email" aria-required="true" />
<label for="fieldSubscribe">Subscribe</label>
<input name="fieldSubscribe" type="checkbox" checked="false" aria-disabled="true" />
</form>

tabIndex

This is one that I vaguely knew about. It turns out that there are three types of values that it can take.

  • tabindex="-1" negative one or less allows elements to get the focus programmatically instead of through sequential keyboard navigation
  • tabindex="0" zero allows non tabbable elements to become tabbable in sequential order by adding focus to them in the document's source order
  • tabindex="1" one or more makes the elements tabbable in the specific index order represented by this number

onKeypress handler

For all the user clickable elements we can also provide an onKeyPress that handles an Enter or Return key on a clickable element. We can use a function to check for that keypress and if it's is the key we're looking for we can pass the event to the onClick function.

Here's a great snippet from John Luke Garofalo's post about React accessibility:

// attach to a onKeyPress to handle Enter keyboard
// presses in the same way as onClicks
export const handleEnterKeyPress = (onClick) => (event) => {
if (event.key === 'Enter') {
onClick(event);
}
};

Here's that snippet in TypeScript:

type HandleKeyPress = (
onClick: React.EventHandler<React.MouseEvent | React.KeyboardEvent>
) => React.KeyboardEventHandler<HTMLElement | SVGElement>;
// attach to a onKeyPress to handle Enter keyboard clicks in the same way as onClicks
export const handleEnterKeyPress: HandleKeyPress = (onClick) => (event) => {
if (event.key === 'Enter') {
onClick(event);
}
};

Conclusion

Hopefully this helps you dip your toes into the accessibility pond. I have a lot more to learn and implement but I feel like this was a good start. I would love to hear your resources if you have started down this road as well.


Discuss this article on Twitter

Category:

dev

© 2012-2023, built with Next.js and Chakra UI

InstagramtwitterlinkedIngithubjoelmturner's DEV Profilejoelmturner's Mastodon Profile