Skip to content
Home Code for everyone – Find & Fix Accessibility Issues in React

Code for everyone – Find & Fix Accessibility Issues in React

Code for everyone

Website and mobile applications accessibility have become a critical requirement in today's digital landscape, as businesses are increasingly relying on these platforms to reach and engage customers. However, many companies have been slow to recognize the importance of accessibility, resulting in a growing number of lawsuits filed by individuals with disabilities who are unable to use these platforms. Accessibility should not be an afterthought; it is an essential aspect of the development process. Developers should keep accessibility in mind so that we can create more inclusive digital products and services that benefit everyone.

There are several guidelines that needs to be followed for making web content accessible & the most popular is Web Content Accessibility Guidelines 2.1 (WCAG). For a new front-end developer, it could be overwhelming to understand WCAG. Since it has 4 principles, 13 guidelines, 78 success criteria’s & each success criteria have multiple techniques and failures.  

So, if you are a React developer who wants to start building accessible websites, today I will cover how you can find accessibility issues when you write the code and fix it very easily, so you ship accessible code! 


Eslint-plugin-jsx-a11y is a plugin which performs a static evaluation of the JSX code to find accessibility issues in React websites. It also provides errors & hints to fix them. It has total 36 different rulesets & few of them can be more customized when used with "recommended" mode. 

Note: For the following steps you will need a code editor like Visual studio Code

Step 1: Let’s create a demo react-app 

Create a demo react app using following command.  

npx create-react-app my-app

Now write some code of your application in App.jsx file which is inaccessible. For instance, we have created navigation links & a sign up form. 

<div className="App"> 
      <div className="app-header">
      <img src="/image/logo.png" className="App-logo" /> 
          <div class="primar-nav"> 
              <a href="/home">Home</a> 
              <a href="/services">Our services</a> 
              <a href="/signup" tabIndex="1">Sign Up</a> 
      <div className="app-content"> 
        <div>Sign up</div> 
          <p>Enter your details below to sign up!!</p>
        <label>First name</label> 
        <input type="text" id="fname" /> 
        <label>Last name</label> 
        <input type="text" id="lname"/> 
        <input type="text" id="email"/> 
        <input type="password" id="password"/> 
          onClick={() => {   
          Sign Up 
Preview of the App.js file with app code

Step 2: Now, let’s Install es-lint package 

To install es-lint package, run the following command in terminal. 

npm install eslint --save-dev

Step 3: Now, Install eslint-plugin-jsx-a11y package. 

To install the eslint-plugin-jsx-a11y package, run the following command in terminal.  

npm install eslint-plugin-jsx-a11y --save-dev

Step 4: Now let’s setup .eslintrc.json & Package.json files 

Create a file with name ".eslintrc.json" in your src folder & write the following code inside the file. It will act as a configuration file for our eslint package. 

{"extends": ["plugin:jsx-a11y/strict"]}

.eslintrc.json file with code

Add the following code inside Package.json file inside "scripts" object. 

"lint": "eslint src"

Preview of Package.json consisting of default scripts

Step 5: Now let’s fire up the engines & take this for a test drive!!  

In the terminal run the command: npm run lint

You will see terminal throws the following accessibility errors along with line number of code where the error is found. 

  • img elements must have an alt prop, either with meaningful text, or an empty string for decorative images 
  • Avoid positive integer values for tabIndex. 
  • A form label must be associated with a control.    
  • Visible, non-interactive elements with click handlers must have at least one keyboard listener.  
  • Avoid non-native interactive elements. If using native HTML is not possible, add an appropriate role and support for tabbing, mouse, keyboard, and touch inputs to an interactive content element. 
Preview of terminal with accessibility errors along with line number & rule names

As a developer, you might be wondering what does each error mean and how should you fix them? No worries! We got you covered! 

How to understand issues & fix them? 

  1. img elements must have an alt prop, either with meaningful text, or an empty string for decorative images 

    Images without alternate text are difficult to perceive for screen reader users. They won’t know if the image exists if alternate text is not given. To fix this issue provide alt attribute to the img element with descriptive alternate text as shown below:

    <img src="images/logo.png" className="App-logo" alt="Company logo" />

    Check out Images tutorial from W3C to learn more about accessible Images.

  1. Avoid positive integer values for tabIndex

    When positive tabindex values are used it creates an unexpected tab order, which makes tabbing order less intuitive for keyboard-only users. In our website when user will navigate through the page with tab key the focus will be set to "Sign Up" link first instead of "Home" link which is appearing first visually. This will disorient keyboard, low vision & screen reader users while accessing the page contents. To fix this issue remove tabindex attribute from anchor element as shown below: 

    <a href="/signup">Sign Up</a>

    Check out tabindex attribute from MDN Web Docs to learn more.  

  1. A form label must be associated with a control 

    The <label> element must be explicitly associated with the respective input control so that the relationship can be determined programmatically by the linter, and a users's assistive technology. The id & htmlFor attributes can be used to associate the input control with a label. To fix this issue associate the labels with respective input controls as shown below: 

       <label htmlfor="fname">First name</label> <input type="text" id="fname" />
     <label htmlfor="lname">Last name</label> <input type=”text” id=”lname” /> 
     <label htmlfor="email">Email</label> <input type="text" id="email" /> 
     <label htmlfor="password">Password</label> <input type="text" id="password" /> 

    Check out Labelling Controls from W3C to learn more. 

  1. Visible, non-interactive elements with click handlers must have at least one keyboard listener.  

    When a non-interactive element such as <div>, <span> & so on are used for interaction which have only click events, they won’t be operable with a keyboard. This will make it difficult for screen reader & keyboard-only users to activate the element. To activate a Button, Enter/Return  or Spacebar keys are used. So, in case of non-interactive element, you need to add a script to listen to these key events. To fix this issue add a keyboard event equivalent to click event as shown below: 

          onClick={() => {
           onKeyDown={(event) => {
           if (event.which === 13 || event.which == 32) {
         Sign Up 
  1. Avoid non-native interactive elements. If using native HTML is not possible, add an appropriate role and support for tabbing, mouse, keyboard, and touch inputs to an interactive element. 

    Non-native elements such as <div>, <span>; and so on do not have any semantic meaning & hence when they are used for interactions on the page it becomes difficult for assistive technology users to understand their purpose. Instead, native interactive HTML elements such as anchor(<a>), button(<button>), form controls like radio button (<input type="radio">) & checkbox (<input type="checkbox">) and so on should be used. 

    If using native HTML elements is not possible then you should provide appropriate roles, states & properties of ARIA along with keyboard support for the non-native elements. To fix this issue provide role="button" & tabindex="0" attributes to the <div> element as shown below: 

         onClick={() => {   
         onKeyDown={(event) => { 
         if (event.which === 13 || event.which == 32) { 
         Sign Up 

Talk to our Accessibility Expert

Fixed all the errors? Let’s test again! 

After fixing all the errors if you run the command npm run lint again you won’t get any errors in terminal & your application will be compiled successfully! 

Preview of terminal displaying compiled successfully! message & the local address

Plugin Modes 

This plugin comes with 2 modes. 

  1. Strict – Enabled by default & offers more rules set by default. 
  2. Recommended – It has less rules enabled by default. Allows some rules to have extra options in this mode. 

You can also create & configure your own custom rules as per the requirements. 

You can read more details about the plugin & other rules in the eslint-plugin-jsx-a11y github page. 

Wait, this is not the end!! 

There are more issues in our code which were not captured by the plugin. Yes that’s true, automated testing can’t identify all the Accessibility errors. So, we will perform a basic manual test to identify the remaining issues. Manual testing is a must when it comes to Accessibility of digital solutions! 

  1. The links such as "Home", "our services", "Sign up" and so on visually look like a list but not marked as list programmatically. Also, these links should be wrapped inside <nav> element along with a unique label which would render as a Navigation landmark for screen reader users. CSS can be used to maintain the presentation of the page.    To fix this issue wrap the links inside an unordered list <ul> & <nav> element. Also provide aria-current="page" attribute to the link which represents the current page within set of navigation links.   
     <nav aria-label="primary"> 
        <li><a href="/home">Home</a></li> 
        <li><a href="/services">Our Services</a></li> 
        <li><a href="/signup" aria-current="page"> Sign Up</a></li> 
  1. The text "Sign Up" inside the main content visually constitutes as a section heading but is not marked as heading programmatically.    To fix this issue mark the text "Sign Up" as heading with <h1> element.    <h1>Sign Up</h1> 

Hence manual testing needs to be performed with keyboard, screen reader & other assistive technologies to find issues which needs human judgment. We also recommend including people with disabilities in your testing process to get overall feedback about their experience. 

There are more automated tools like ANDI, WAVE and so on which can be used to find more accessibility issues on the rendered output. 

Note that these were simple elements & accessibility can be implemented even for complex interactions like search, drag & drop and so on. 

Accessibility in React official documentation also has more detailed information on how you can implement accessibility in React based websites. 

To summarize,  

  1. We wrote code that was not accessible. 
  2. Setup the eslint-plugin-jsx-a11y plugin. 
  3. Ran the test & got the a11y errors inside terminal. 
  4. Understood about the errors & how to solve them. 
  5. Fixed our code & compiled successfully.  
  6. Congratulations!! You successfully shipped accessible code because coding for accessibility isn’t difficult! 

Looking for a reliable digital accessibility partner that can help you help you think accessibility first and build accessibility features into your digital products? Write to us at or schedule a consultation with our accessibility expert.

This article by Siddharaj Suryavanshi is a part of our BB Geek series where BarrierBreak team members share their expertise on accessibility and inclusion, drawing from their extensive experience in the field.

Leave a Reply

Your email address will not be published. Required fields are marked *

Back To Top