Developers love to debate frameworks and libraries. As accessibility advocates, it’s important to us that accessibility is considered in these debates. The common question is: “Is React accessible?” But that’s not quite the right way to think about it.
To be sure, accessibility challenges are not unique to React. And like any other framework or library, there are accessible and inaccessible React implementation examples. The more relevant questions are:
- Does React make building accessible apps easier or harder?
- Is the average React site or application accessible? And if not, why?
Our testing experience
As testers, we usually don’t see the web at its most accessible. Our experience testing React-based sites is no different. But we do see some common patterns of inaccessibility in React. Some of these are due to developer habits and others are attributable to the way React itself functions.
Poor use of semantic HTML
While it is possible to make use of semantic HTML in React, it is rare in our experience. Instead of using semantic elements like <header>
, <nav>
, <button>
, <h2>
and <p>
, React developers often rely on styled
(generic container) elements for all of those use cases. As a result, screen readers could lack insight into the meaning of significant portions of a React-based site; instead of announcing a heading, the screen reader just sees a generic text snippet.<div>
Some of this is inherent to React. React uses JavaScript XML (abbreviated as JSX) as a way of writing pseudo-HTML to define build UI structures. Combine this with the perception that <div>
elements offer more flexibility and ease of styling,and the outcome is understandable. Since React doesn’t enforce semantic correctness, it’s not surprising that developers don’t use the proper HTML elements designed for a given purpose.
But while React makes it easy to overuse the <div>
element, it’s also important to realize that React developers are not necessarily all making the same error independently. One reason we see these errors repeat frequently is that they are literally copied and pasted. In a world where many developers use popular UI libraries (and never learn semantic HTML), they can easily inherit bad practices without realizing. (And even when coding from scratch, developers exposed to these patterns are prone to repeating them without realizing there is an issue.)
Subscribe to our Newsletter
Div soup
We’ve discussed why <div>
is overused and why that is inaccessible. But another feature of React architecture is that it encourages componentization. This has many benefits. It is indeed a feature! But it comes with downsides as well.
As components are nested within other components (and those components are nested too), React markup is messy. And since these components are frequently built with <div>
elements, this compounds the accessibility issues. It’s common to encounter 5 or more layers of nested <div>
elements, which makes it even harder for screen readers to understand the structure and for keyboard users to navigate.
Over-reliance on ARIA
For developers (and even libraries) that try to mitigate these common React inaccessibility patterns, it’s common to turn to ARIA (Accessible Rich Internet Applications), a set of HTML attributes that add accessibility metadata to markup. In other words, where screen readers lack information to properly describe or interact with HTML, ARIA can help bridge the gap in providing accurate information about an element’s purpose or state. ARIA can be an important accessibility tool especially in scenarios where HTML doesn’t natively support certain roles or states.
For example, in a React application, a developer might add a role="button"
attribute to a <div>
that visually resembles a button.
<div role="button">Click me</div>
Seems great! So what’s the problem?
ARIA adds semantic metadata for screen readers but doesn’t replicate any of the other functionality inherent to semantic HTML. For our button example above, adding a button role tells screen readers it is a button but doesn’t actually allow keyboard users to interact with the button. Additional code would be needed to support that function.
<div class="custom-button" role="button" tabindex="0"
onclick="alert('Button clicked!')"
onkeydown="if(event.key === 'Enter' || event.key === ' ') this.click();">
Click Me
</div>
Not so simple anymore! In contrast, using the <button> tag gives you everything you need out of the box.
Developers also frequently misuse ARIA by using inappropriate roles that actively mislead screen reader users. Furthermore, the full ARIA specification is not supported across all browsers. That isn’t necessarily an issue for the “button” role but digging into the ARIA specifications without understanding ARIA may not actually work. There is a reason that the first rule of ARIA is that “No ARIA is better than bad ARIA.”
SPA focus management issues
Another common React accessibility issue relates to how Single Page Applications (SPA) handle navigation between pages. On traditional multi-page architecture websites, users can click links to open a new page. The new page actually loads in the browser and the keyboard focus automatically resets to the top of the page. The screen reader announces the new page title and keyboard users can immediately start from the top.
SPAs have a different default behavior. Clicking a link can change the page content (and even the URL) without actually loading a new page. Without a new page announcement, screen reader users may be unaware that the page has changed. Furthermore, the keyboard focus remains in the same place, which means the users find themselves in the middle of the page without context.
This behavior can be changed from the default, but developers need to first recognize the issue and understand how to implement the update.
Poor performance is inaccessible
React-based sites rely on client-side rendering, which means that code runs in the user’s browser to process and render the page. (In contrast, server-side rendering does this work before serving the page.) It’s not terribly surprising that this impacts initial load times for everyone. (And this doesn’t even take into account that poorly optimized React sites can be bloated with unused code that the user must download.)
But it disproportionately affects people with disabilities. Screen readers may announce blank content while waiting for JavaScript to fully load. Users with disabilities may be using older or low-power devices that struggle with client-side processing. Users with cognitive difficulties may be particularly frustrated by slow or janky UI updates. These performance lags can be worsened for screen reader users and other assistive technologies.
What should developers do?
React is one of the most popular frameworks in the world and there are of course good reasons why some organizations may prefer or need to build SPAs (whether on React or another framework). This decision may already be locked in when you start work.
But if you are in a position to make early technical decisions, choosing React by default does not necessarily lead to accessible user experiences. But for projects that are primarily static content, avoiding SPAs altogether in favor of server-side rendering or static site generation (pre-rendering) may be the best approach. And if SPA functionality is necessary, consider whether other frameworks like Vue can fit your needs.
However, as we noted at the start of this article, is it possible to build accessible experiences in React (even if there are barriers to overcome). Start by incorporating some of these strategies:
- Replace generic
<div>
elements with semantic HTML. Avoid using ARIA when feasible. - Leverage React Fragments to group elements to reduce unnecessary
<div>
wrappers. - Manually manage route changes so that focus is reset to the top of the screen and new page titles are announced.
If you are starting new components from scratch, choose your libraries and component frameworks carefully. Some React libraries are more accessible and it’s great to utilize solutions that incorporate accessibility by default instead of requiring remediation. Ideally, you should test these components for accessibility yourself, but we recognize that library users are not starting from a position where accessibility testing falls within their skillset. Our recommendation is to read these React libraries’ documentation closely; those that reference the considerations we’ve discussed in this article are likely to lead you in the correct direction.
Get a free manual accessibility review
We can help make your React application more accessible. Get the process started with no further obligations.
Get your free assessment