Web Accessibility in React
Web Accessibility is a field of work focused on removing obstacles that often arise when a disabled person interacts with websites and apps. If they are well-designed and coded in line with the principles of semantic HTML and accessibility rules, then we have bigger chance that all users will enjoy equal access to information and functionalities.
How does a disabled person use the web apps?
According to the WHO, around 15% of people all over the world live with some kind of disability. There are four main categories of disabilities, and each of them require specific technologies, tools and programs for the disabled person to be able to take full advantage of the benefits of the Internet.
Categories of disabilities:
Visual disability— sight impairment, short-sightedness, blindness
- use of screen readers or braille readers to interact with a web page
- use of zoom on web page display, use of high contrast setting
Motor disability— injuries, RSI, paralysis, movement limitations
- use of programs and tools scanning eye and head movements for website navigation
- voice commands
- switches
- Switch Access (Android)
Hearing disability— partial or complete hearing loss
- sharing transcriptions and sound information
Cognitive / intellectual disability— ADHD, dyslexia, autism and others
- for instance, people with dyslexia can make use of a browser extension which puts different color gradients on chunks of text to make them easier to read
What is important when writing an accessible app?
It is vital to understand that accessibility is not an optional part of an app, but rather a necessary and inherent one. It is also vital to consider the needs of the end users — the disabled, and how those needs should be met in the process of using the app.
WAI (Web Accessibility Initiative) is an initiative by W3C (World Wide Web Consortium). Its goal is to improve the accessibility of the Internet for the disabled, e.g. by sharing the rules, specifications and guidelines as to what is the process of writing an accessible web page or app. Below are listed some of the selected documents and specifications:
- WCAG 2.1 — document including the information on how to build an accessible web application for everyone
- WAI-ARIA — a technical specification describing the set of recommendations on improvements of accessibility within complex web applications
The above-mentioned specifications are vast documents with substantial number of pages, however, comprehensive summaries can be found on the Internet.
Additional perks to writing accessible code:
- Better sales opportunities with accessible sales apps due to a wider range of potential customers (and higher risk of getting negative feedback with non-accessible solutions).
- Current EU legislation on accessibility on public institutions’ websites impose a set of requirements that need to be met. Such regulation may expand on private venture in the future and it is best to get ready in advance.
Real-life example of writing an accessible application
First, let’s recap once again what screen readers are and what is their role.
To put it simply, a screen reader is a part of AT (assistive technology) and it is a computer program used for text processing (e.g. on a website). It is also able to read it aloud thanks to speech synthesizer. It is an indispensable tool for the visually disabled.
There is a lot of similar software on the market, JAWS, VoiceOver, Talkback and NVDA, to mention a few.
In our basic application we will use ChromeVox extension to the Chrome browser as our screen reader.
Let’s fix our inaccessible app
What should you pay attention to while writing accessible apps in React?
- Some of HTML attributes, like
class
, orfor
are slightly different in JSX: they are in camel case style and wording is different:className
,htmlFor
- ARIA attributes in JSX are written in the same manner as in HTML: e.g.
aria-label
- To set focus on something we can use Refs which gives access to DOM
- Of course, React fully supports HTML so using appropriate semantic tags or attributes is highly recommended.
Navigating through the page using Tab key and focus on interactive elements
https://www.w3.org/WAI/WCAG21/quickref/#predictable
One of the basic principles of writing accessible web app is to check the navigation through the website with Tab key. Navigating should be consistent and logical. Focus on interactive elements like inputs, links, buttons, should also be visible. Unfortunately, the focus is invisible in our application, because outline
is turned off for all inputs and buttons:
input, button {
outline: none;
}
Let us then delete this property from the source code.
Now, after pressing the Tab key, we can see which input or button is currently active.
Note: We are not forced to using outline
property implemented by user-agent. In order to change it, we must set the property to value: outline: none
, and additionally define our own styles using a pseudo-class :focus
.
Description of the elements included in the form
https://www.w3.org/WAI/WCAG21/quickref/#labels-or-instructions
Inputs, checkboxes, radio buttons and others should be connected with a <label>
tag.
In our code, it looks like this:
<label className="label">Name</label>
<input className="input" type="text" />
Let’s take a look at what the Chrome Vox reader tells us. When reaching the first field with the Tab key, the only words we hear is “Text editing” and that does not inform a blind person which field is going to be edited.
It’s a bug resulting from lack of connection between the input and the label. One of the ways to combine those tags together is by adding an htmlFor
attribute to <label>
and id for <input>
the same value.
<label htmlFor="name" className="label">Name</label>
<input id="name" className="input" type="text" />
It will make the tags connect and what we will hear now is “Name, text editing.”.
Additionally, the clickable field for this input has become larger, which helps the users with motor disability, because after clicking on a label, the focus will center on the text input connected to that label.
Note: Unfortunately, it often appears that we don’t have a label for editable field on our proposed design. It does not mean that we shouldn’t include it in the code. Is it enough then to set visibility: hidden
or display: none
for <label>
? It’s a good direction, but such actions would make <label>
invisible also for the screen reader. The best solution is to use a certain trick: to hide it visually, but not for the screen reader.
The style of the hide-element
class:
.hide-element {
border: 0;
clip: rect(1px 1px 1px 1px);
clip: rect(1px, 1px, 1px, 1px);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
We add a class with those properties to the label, which allows the screen reader to read the value from the label.
Required fields using aria-required
attribute from the ARIA attributes set.
https://www.w3.org/WAI/WCAG21/Techniques/aria/ARIA2
What is ARIA (Accessible Rich Internet Applications)?
ARIA is a technical specification, containing a set of recommendations concerning improvement of accessibility for complex Internet applications. It includes some special accessibility attributes, which can be included in the HTML code.
A text input with required
attribute has been used in the application, which allows the native browser field to launch.
<input id="name" className="input" type="text" required />
The problem is, however, that a blind person can’t know that this field is required. In order for the screen reader to be able to know that, we must add aria-required={true}
.
<input ... aria-required={true} />
Accessible modal
https://www.w3.org/TR/wai-aria-practices/examples/dialog-modal/dialog.html
After entering values into text fields E-mail and Password, followed by clicking Send button or pressing Enter, the modal appears. How does it look from the accessibility point of view? Let’s check it on our ChromeVox example. Sadly, after clicking Send button, we don’t get any feedback on the modal, we only hear the word “Send”, since the focus remained on this button.
- Setting the focus on the modal
First, we will need refs to access DOM, or rather, to the node representation of the modal in DOM, and in case it gets opened, we need to set focus and corresponding tab-index
on it.
------- index.jschildRef = React.createRef() // create Refs
...
<Popup ref={this.childRef} // attach created Refs to componenthandleSubmit = e => {
...
this.childRef.current.focus(); // set focus after click------- Popup.js // use Forwarding Refsconst Popup = React.forwardRef(({ isOpen }, ref) => (
...
<div
tabIndex={isOpen ? 0 : -1} // if open then tab-index="0"
ref={ref}>
...
);
In this case Refs grants us access to the modal, which in this case is <div>
tag, being a building block for the modal. We can set the focus on it using focus()
function. However, <div>
has no implemented focus by default and the outline
won’t show. tabIndex
can help us overcome this problem and force it to show. When setting tabIndex={0}
, we ensure that the element is taken into account during navigation.
- Adding
role="modal"
<div class="popup" role="dialog">
ARIA makes available a role
attribute with various values, which enable the transfer of information on the importance of an HTML tag to the assistive technology. The vast majority of HTML tags already have a native role and a significance. For instance, the <button>
tag means a clickable button, and <header>
is an introductory content. By adding role="dialog"
, we tell the screen reader that it’s dealing with a modal.
- Closing modal button — changing
<div>
for<button>
, addingaria-label
andaria-hidden
Visually, the “X” sign gives us a clear hint that it serves for closing the modal. However, the button is entirely inaccessible, because the screen reader has no clue whether it’s actually a button there and what is its purpose.
Errors:
- a semantically empty
<div>
tag has been used - lack of focus
- the “X” sign used inside is just a character “X” for the reader
<div className="close-popup" onClick={handleClosePopup}>X</div>
First two problems can be solved very easily by changing tag <div>
for <button>
<button className="close-popup" onClick={handleClosePopup}>
X
</button>
The “X” sign problem can be solved by adding to <button>
an aria-label
attribute with text value what is the function of the button; and at the same time, by enveloping the “X” sign in <span>
tag and hiding it for the screen reader with aria-hidden
attribute.
<button
className="close-popup"
onClick={handleClosePopup}
aria-label="Close modal"
>
<span aria-hidden>X</span>
</button>
- Exiting modal with Esc key
The function disableListEsc
is listener on the whole document and the function listenerOnEscKey
lets us check if Esc
key has been pressed.
disableListEsc = () => {
document.addEventListener('keydown', this.listenerOnEscKey);
}listenerOnEscKey = evt => {
if (evt.key === "Escape") {
this.setState({ isOpen: false });
}
};
The pop-up has been fixed. Now, when clicking the Send button, the voice synthesizer tells us: “You have opened a dialog box, mail has been sent.”. We learn about the modal that’s been created, and at the same time we hear the text content of the modal being read aloud.
The result of the improved application
Helpful tools in process of writing accessible applications
During the development phase, it is worth to equip ourselves with modules or extensions, which facilitate writing code according to the website accessibility guidelines.
https://github.com/reactjs/react-a11y — a tool to set what kind of potential mistakes we want to be informed about, for instance, when we forget to add alt
attribute to <img>
tag
https://github.com/evcohen/eslint-plugin-jsx-a11y — ESLint extension
https://chrome.google.com/webstore/detail/axe/lhdoppojpmngadmnindnejefpokejbdd — Chrome extension
https://developers.google.com/web/tools/chrome-devtools/accessibility/reference#pane — Accessibility pane in Chrome
https://developers.google.com/web/tools/lighthouse/#devtools — Accessibility audit with Lighthouse in Chrome
https://chrome.google.com/webstore/detail/funkify-%E2%80%93-disability-simu/ojcijjdchelkddboickefhnbdpeajdjg — a plug-in simulating various disorders, such as dyslexia, short-sightedness, etc.
https://www.w3.org/WAI/ER/tools/ — list of other similar and interesting tools
Comparing the two application versions in Accessibility Audit in Chrome
Before:
After:
Why is the score only 88, and not 100? Because the audit discovered that contrast between background and label text color is too low.
https://www.w3.org/WAI/WCAG21/quickref/?versions=2.0#qr-visual-audio-contrast-contrast
But that’s designer’s job to get the colors right 😉
Note: of course, we could add a contrast-changing feature, but the colors should be set with adjusted contrast by default
Has the app become accessible for every user?
It certainly has become more accessible compared to what was before and has substantially improved in terms of accessibility and usability for the disabled users.
The audit brought up before indicated the accessibility score of 88 out of 100. We would have reached 100/100 after correcting the contrast issue, however, it does not imply that the application is accessible for each and every user in the world. What is important here is the message produced by the audit: “These checks highlight opportunities to improve the accessibility of your web app. Only a subset of accessibility issues can be automatically detected so manual testing is also encouraged.”. What it means, is that a crucial part of testing the application’s accessibility is to run a manual test, preferably carried out by a disabled user.
Additionally, during the improvement of the application, we have adopted blind and short-sighted users’ point of view while using the screen reader. It was a good approach, given such an easy example, yet with more complicated applications, a lot of different requirements need to be met. There are many kinds of disabilities and the WAI rules specify numerous different guidelines, such as sans-serif font (for people with dyslexia), larger clickable area on interactive elements (for people with motor disability), or coherent and predictable application format (for people with autism).
Useful links / bibliography
https://developer.mozilla.org/en-US/docs/Web/Accessibility
https://inclusive-components.design/
Pro HTML5 Accessibility — Joshue O Connor