Spending some time making your React app accessible can help ensure a wider range of people can use all the amazing interfaces you’re building. Thankfully, improving how accessible an app is often requires only minor changes to your components.
Building accessible apps means helping as many people as possible interact with your app’s interface. This includes individuals with auditory, cognitive, neurological, physical, speech, and visual impairments. It can also include temporary conditions, like a broken wrist, that may prevent someone from interacting with an app how they usually would.
“a11y” is a numeronym for “accessibility”. It refers to the first and last letters, and the 11 letters in between. 🤓
The short answer is that accessibility is for everyone! ✨ Accessible apps often have better user experience (UX) because they have more intuitive interactions. High colour contrast, for example, makes reading text easier for everyone–not just someone with a visual impairment.
Accessible apps improve the UX for everyone, not just those who interact with apps differently than the “average user”.
Thankfully, there’s nothing inherently inaccessible about React. Given that React apps are component-based, though, it can be easy to lose track of how accessible your app is from a broader view.
Let’s look at five specific ways to make React apps more accessible.
Semantic markup is HTML that uses elements titled for their purpose.
Most of us React developers have gotten pretty comfortable with our trusty div
elements. Ditching the div
and using semantic HTML instead can be incredibly helpful for a couple reasons, though:
To see why semantic HTML is useful, let’s first look at an unordered list component using only div
s:
...
render() {
return (
<div>
<div className='title'>
Favourite Foods
</div>
<div className='list'>
<div className='item'>
- Sushi
</div>
<div className='item'>
- Pizza
</div>
</div>
</div>
)
}
It’s not immediately clear what this component is unless the classes and structure are considered. The screen reader definitely can’t tell what these elements are supposed to be so we can consider this list pretty inaccessible. 🙈
Let’s try this again with semantic HTML now:
...
render() {
return (
<section>
<h2>Favourite Foods</h2>
<ol>
<li>Sushi</li>
<li>Pizza</li>
</ol>
</section>
)
}
As a developer, we can now clearly see what these elements are and the screen reader knows their purpose as well.
As a default, try to use elements other than div in your components. There are often better options that can greatly improve accessibility and readability (like header, footer, section, aside, etc. ✨)
ARIA stands for Accessible Rich Internet Applications. ARIA attributes aren’t required and can instead be considered a supplement to help the HTML be read by a variety of devices.
As we’ve seen above, semantic markup makes your codebase more readable for screen readers. We can get even more specific now with ARIA attributes.
Let’s say we get instructions to add a button that increments something. One option would be to make a div
and add an onClick
event to it like so:
...
render() {
return {
<div>
<div>Increment Something</div>
<div onClick={this.incrementSomething}>
+
</div>
<div/>
)
}
Unfortunately, the screen readers won’t know this component is a button or that the label is related to it.
Now let’s look at a more accessible version:
...
render() {
return (
<button
onClick={this.incrementSomething}
aria-label='Increment Something'>
+
</button>
)
}
Compared to the first example, the screen reader now knows it’s a button because we’re using a native HTML button. It can also tell the user what the button does from the aria-label
. 💪
Now let’s say you can’t convert your component to a button for some reason or you want to keep the label in the user interface (UI). No problem. We can use the role
and aria-labelledby
attributes to keep the the screen reader in the loop.
...
render() {
return (
<>
<h3 id='incrementButtonTitle>
Increment Something
</h3>
<div
onClick={this.incrementSomething}
role='button'
aria-labelledby='incrementButtonTitle'>
+
</div>
</>
)
}
The role
prop tells the screen reader the element should be read as a native HTML button, and the aria-labelledby
attribute says the element with that ID (the <h3>
) is the button’s label. 🎉
The browser’s default focus styling isn’t the prettiest styling you’ll see but it’s incredibly helpful for navigating apps with your keyboard.
To see the your browser’s focused styling, try hitting Tab a few times now and you should see a border around the currently focused element.
After tabbing a few times, imagine that border was not around that link in the nav bar and you couldn’t use your mouse. When there are no visual indicators of what is currently focused, it’s nearly impossible to select the intended element.
The easiest solution is to always leave the browser’s default focus styling. Alternatively, if the default styling doesn’t fit your designs, override the default styling with custom styling like this:
a.nav-links:focus {
outline: 0;
border-bottom: 2px solid pink;
}
In general, the web is inherently accessible. Design decisions, like removing focus styling, can reduce a website’s accessibility. That means a lot of the work is already done for you if you leave those default styles! 🌈
Letting people navigate your app using just their keyboard is a great way to improve accessibility.
One way of doing this is to take advantage of the tabindex
attribute. It allows the developer to control the order of elements focused while tabbing outside of the default order.
Only elements that can be interacted with (like an input) are included in the tab order.
By default, the tab order is the order of elements as they appear in the DOM.
...
render() {
return (
<footer>
<a href='#link1' tabindex='3'>
first
</a>
<a href='#link2' tabindex='2'>
second
</a>
<a href='#link3' tabindex='1'>
third
</a>
</footer>
)
}
In this case, instead of tabbing through the links in the order they appear (first, second, third), the tabindex
controls the order (third, second, first).
There are a few ways to change the default tab order:
tabindex
is read sequentially, with tabindex='1'
being the first to received focus (then 2, 3, 100, etc.).tabindex='-3'
) but is uncommon for improving accessibility.tabindex
of zero/0 will allow a user to tab to an element that can’t be tabbed to otherwise. This can be useful if you’re unable to use semantic HTML.Always test the UX of adding a tabindex to your React components to make sure it helps users more than it hinders them. If your HTML is semantic, you shouldn’t need tabindex.
The alt
(or “alternate”) attribute is another quick way of making your React app more accessible. When a screen reader reaches an image, it will read out loud the alt
text to provide a description of the image’s content.
const AlligatorImg = () => (
<img
src='./img/alligator.png'
alt='Alligator coming out of water with mouth open'
/>
)
The purpose of the alt
text is for the person hearing it to understand the content of the image. It should be specific enough that the person can imagine the image without seeing it.
Your alt text doesn’t need to include phrases like “Picture of” or “Image of”. The screen reader already knows it’s a picture because it’s an image element, so there’s no need to add that! 🤓
As a general rule, try to keep your alt
text concise (about 20-100 characters) but still descriptive. Being too concise (like alt='alligator'
) won’t tell your user very much about the photo.
Overall, accessibility is a big topic and there are many ways to maximize how many people can use all your amazing React apps.
If you’d like to do a deeper dive, check out the WAI (Web Accessibility Initiative) for more tips.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!