Writing accessible apps and efficient code with React fragments

Introduction

 In this article, you will be introduced to an awesome feature in React called fragments. You will learn why it is important as regards accessibility and how to use it.

Sometimes while using React, you want to display or return multiple HTML elements in a component. This can be achieved in a number of ways that will be discussed in this post, most of which however can lead to HTML that is not accessible or even to writing non-semantic code. In this article, you will be shown a new feature called fragments in React that lets you do so in a very accessible memory efficient way. You will be taken through a series of illustrations and also code samples to let you properly understand the usefulness and how React fragments came about.

Achieving accessibility in React

Web accessibility involves designing pages, tools, and technologies that are inclusive for all users. This includes individuals with hearing, cognitive, neurodivergent, mobility, speech, and vision differences. Accessibility support is necessary to allow assistive technology like screen readers to interpret web pages and applications. For these technologies to work, developers have to always think and build accessible applications.

Prerequisites

This article is suited for all levels of expertise using React JS, this includes beginners. This article promises to break down concepts as simply as possible.
To be able to follow through in this article’s demonstration you should have:

  • Visual Studio Code installed as your integrated development environment.
  • Node version 11.0 or above installed on your machine.
  • Node Package Manager version 6.7 or above (usually ships with Node installation).
  • React version 16.8 or above installed on your machine.
  • Create-react-app installed on your machine

With these, you are ready to move to setting up a new React project.
Other things that will be nice-to-haves are:

Setting up

We will go through the process of setting up the development environment and installing all the required dependencies for create-react-app to work.

Install React globally by running the command below in a terminal:

    npm install -g react

Install create-react-app globally too with this command below

    npm install -g create-react-app

Navigate to a folder of your choice and create a new React application called fragments with the CRA boilerplate by running this command below

    npx create-react-app fragments

OR You can just download an already created new React project here. Unzip the folder and then install all the dependencies with this command:

    npm install

Navigate into the fragments folder and run the new app in development environment like this:

    npm start

Open the project in VS Code, navigate to the src folder and open the app.js file. Remove all the code inside the div of the return statement. Your app.js file should look like this:

1//  src/App.js
2    import React, { Component } from 'react';
3    import './App.css';
4    class App extends Component {
5     render() {
6      return (
7      <div className="App">
8      </div>
9      );
10     }
11    }
12    export default App;

Writing in JSX

Create a new file, call it Fragment.js It will be a React component. Writing in JSX, if you want to return a paragraph of text with a heading in a functional or any React component, you might first think to represent it like this at first:

1// src/Fragment.js
2    import React from 'react'
3    function Fragment() {
4    return (
5    <h2> Learning about fragments </h2>
6    <p>fragments are super amazing</p>
7    )
8    }
9    export default Fragment

Add this line to the App.js to import the fragment component in the main app component

    import Fragment from './Fragment';

You will immediately see some warnings in squeaky red lines saying “Parsing error: Adjacent JSX elements must be wrapped in an enclosing tag” and if you go ahead and save the file and run in the development environment, you will find out the application is broken.

react-fragments-1

This occurs simply because it is not possible to have more than one parent HTML element in a return statement for JSX. In order to run JSX code and get it compiled, it must have one parent HTML element, and the rest of the elements should be child elements of that parent element. There has been a few ways React developers over time have used to get around this problem, I call them old practices.

Old practices

These are a few practices usually adopted by React developers to return multiple HTML elements without any parse errors.

The array technique

In this technique, you wrap the elements you want to return in an array by passing the elements like array elements. That way, your elements will be rendered as you will want them and the application will no longer break.
Create a new functional component and call it ArrayExample.js . Return the exact logic we had in the first illustration in the return section but this time as array elements of an array.

1// src/ArrayExample.js
2    import React from 'react'
3    function ArrayExample() {
4     return (
5      [
6       <h2>Learning about fragments</h2>,
7       <p>fragments are super amazing</p>
8      ]
9     )
10    }
11    export default ArrayExample

Reference this new component in the DOM by including it and importing it in the main App.js file.

1// src/App.js
2    import React, { Component } from 'react';
3    import './App.css';
4    // import Fragment from './Fragment';
5    import ArrayExample from './ArrayExample';
6    class App extends Component {
7    render() {
8    return (
9    <div className="App">
10    {/* <Fragment /> */}
11    <Array />
12    </div>
13    );
14    }
15    }
16    export default App;

In order not to get any errors, make sure to remove the paragraph element in the Fragment.js file. The return statement should look like this:

1// replace the return code block in the Fragment.js with this
2    return (
3    <h2>
4    Learning about fragments
5    </h2>
6    )

When you save all the files, you will see the elements you expected rendered in the browser. Open your browser at http://localhost:3000/ and you should see your application like this:

react-fragments-2

Drawbacks: inefficient memory management

The array technique is a good solution but a memory inefficient solution, as it requires rendering extra elements in the DOM. It also requires even more additional syntax to use. If you use your browser developer tools to inspect the application, you will see a console warning that looks like this:

react-fragments-3

To make sure you do not get warned again, add unique keys to the individual elements in the array.

1// src/ArrayExample.js
2    import React from 'react'
3    function ArrayExample() {
4     return (
5      [
6       <h2 key="alpha"> Learning about fragments </h2>,
7       <p key="beta"> fragments are super amazing </p>
8      ]
9     )
10    }
11    export default ArrayExample

You will see the warnings disappear when you save the file. This additional syntax adds to the cumbersome nature of this method and makes it unsustainable and inefficient.

The extra tag technique

Another solution to returning more than one element without errors is to wrap them in a parent tag. This tag can be a span or a div tag, most React developers use div tags a lot to ensure their code block for a return statement does not lead to errors that break the application. These tags are absolutely do nothing except preventing JSX errors.

Create a new functional component and call it Extra.js. Copy the logic below and paste into the new component.

1// src/Extra.js
2    import React from 'react'
3    import Lists from './Lists';
4    function Extra() {
5     return (
6      <div>
7       <h2> Learning about fragments </h2>
8       <p>Ways to render elements</p>
9       <ul>
10        <Lists />
11       </ul>
12      </div>
13     )
14    }
15    
16    export default Extra

Create another component, call it Lists.js where the list will be stored and then imported into the Extra component.

1// src/Lists.js
2    import React from 'react'
3    function Lists() {
4     return (
5      <div>
6       <li>1. Array method</li>
7       <li>2. Extra tag method</li>
8       <li>3. fragments</li>
9      </div>
10     )
11    }
12    export default Lists

Reference the Extra component in the DOM by including it and importing it in the main App.js file.

1// src/App.js
2    import React, { Component } from 'react';
3    import './App.css';
4    // import Fragment from './Fragment';
5    import Extra from './Extra';
6    
7    class App extends Component {
8     render() {
9      return (
10       <div className="App">
11       {/* <Fragment /> */}
12       {/* <ArrayExample /> */}
13       <Extra />
14      </div>
15      );
16     }
17    }
18    
19    export default App;

When you save all the files, you will see the elements as expected rendered in the browser. However, when you inspect the application using the developer tools you will discover that the extra div is present in the DOM but more damaging is the div between the ul tag and the li tags. That is not semantic and will not be recognized by an accessibility tool like a screen reader.

react-fragments-4

You can see that after a ul tag, the next logical HTML tag to expect is either li or a closing ul tag. Any other tag will deviate from HTML semantics.

Drawbacks: accessibility problems

This is the most popularly used method but it is also the most inaccessible solution. In instances like rendering lists items where we use extra elements like div tags are used, it can easily lead to non-semantic HTML. As regards to accessibility, which will be explained later in this post, it is very difficult for screen readers to interpret non-semantic code and so this method, albeit simple is not advisable.

Introducing React fragments

Some months ago, React version 16.2 was released, it shipped with this new feature that helped to address this accessibility problem called fragments. Fragments are like those extra HTML elements we used but they come without all the drawbacks. This means that child nodes can be returned safely without extra nodes added to the DOM.

Fragments let you group a list of children without adding extra nodes to the DOM — Official Documentation

Fragment syntax

1render() {
2      return (
3        <React.fragment>
4          <ChildA />
5          <ChildB />
6          <ChildC />
7        </React.fragment>
8      );
9    }

There is also a shorthand syntax you might have noticed in some of my React tutorials, they look like this:

1render() {
2      return (
3        <>
4          <ChildA />
5          <ChildB />
6          <ChildC />
7        <>
8      );
9    }

Applications of fragments

If you take the very first illustration we addressed which is Fragment.js and wrap the elements in a React fragment, you will see no errors and they will compile without adding the fragment node to the DOM.

1// src/Fragment.js
2    import React from 'react'
3    function Fragment() {
4     return (
5      <>
6       <h2> Learning about fragments </h2>
7       <p>fragments are super amazing</p> 
8      </>
9     )
10    }
11    export default Fragment

Save the file and take a look at the element inspection in the developer tools, you will notice the beautiful power of fragments.

react-fragments-5

The elements appear in the DOM exactly as they are in the presentation and no longer contain any extra elements. Fragments can be used to improve efficiency, better manage memory and reduce cumbersome code structures.

Keyed fragments

React fragments can be returned by callback functions and they can have a key attribute. Copy the code below to the Fragment.js file

1// src/Fragment.js
2    import React from 'react'
3    function Fragment() {
4    const artists = [
5    {id: '1', name: 'Davido', genre: 'afro pop'},
6    {id: '2', name: 'Skepta', genre: 'afrobeats'},
7    {id: '3', name: 'Burna Boy', genre: 'afro pop'},
8    {id: '4', name: 'Mr. Eazi', genre: 'afro pop'},
9    {id: '5', name: 'Stormzy', genre: 'afro pop'},
10    {id: '6', name: 'Wizkid', genre: 'afro pop'}
11    ]
12    return (
13    <>
14    <h1>UK Urban Artists Chart</h1>
15    {
16    artists.map( artist => (
17    <React.Fragment key={artist.id}>
18    <h2>{artist.id}: {artist.name}</h2>
19    </React.Fragment>
20    ))
21    }
22    </>
23    )
24    }
25    export default Fragment

The key attribute is the only attribute that can be passed to React fragments at the time of writing this tutorial. The React team however promised to look into adding support for more attributes like event handlers.
Make sure to uncomment the fragment import in the App.js file

1// src/App.js
2    import React, { Component } from 'react';
3    import './App.css';
4    import Fragment from './Fragment';
5    // import ArrayExample from './ArrayExample';
6    // import Extra from './Extra';
7    
8    class App extends Component {
9     render() {
10      return (
11       <div className="App">
12        <Fragment /> 
13       </div>
14      );
15     }
16    }
17    
18    export default App;

Save all the files and your application should look like this:

react-fragments-6

Conclusion

In this tutorial, you have been introduced to React fragments, why they are important and how they are used. You have also seen how they contribute to ensuring we keep building accessible applications. The coming of fragments is one deliberate step towards achieving total accessibility championed by React. You can find my how to make your React application more accessible article here. The complete code to this tutorial can be found on GitHub here. Try using fragments today.