DEV Community

Cover image for The state of semantic JSX
Brian Neville-O'Neill
Brian Neville-O'Neill

Posted on • Originally published at blog.logrocket.com on

The state of semantic JSX

Written by Obinna Ekwuno✏️

Creating platforms for the web has always been as simple as learning to write HTML, throwing in look and feel with some CSS, and then, possibly a bit of JavaScript or any other scripting language for functionality.

However, with the advent of JavaScript component frameworks, a lot of concepts have come into play, such as styled-components and JSX(React) (along with many others). The most interesting part of these frameworks is breaking down webpages into specific components and importing them only when they are needed by the interface from the user.

This begs the questions, does this affect the way the web works? Does it make it better? Can we still write semantic code? Does the single entry point into the component make it hard to get an accessible DOM tree? Let’s find out.

TL;DR

In this article, we will be implementing accessibility features in ReactJS applications. We will look at how to achieve this in component-based applications while avoiding unnecessary div importations using React Fragments. We will also be looking at the concept of focus management and how ref helps to implement this in ReactJS.

LogRocket Free Trial Banner

Prerequisites

Before we go any further, this article assumes the following:

  • Node.js ≥v6 is installed on your machine
  • npm is installed on your machine
  • React version 16.8 or above is installed on your machine
  • Create-react-app is installed on your machine
  • You have basic knowledge of web accessibility
  • You have a basic understanding of ReactJS

Accessibility

Making a web project accessible can feel overwhelming, but it’s really just as simple as implementing a more semantic approach to writing code to enable all users. The foundation for this is the POUR principle which guides building accessible websites.

Simply put POUR means – Perceivable, Operable, Understandable, Robust.

Perceivable : This means the web should be available to the senses (vision, touch, and hearing) either through the browser or through assistive technologies like screen readers and screen enlargers.

Operable : This means users can interact with all controls and interactive elements using either the mouse, keyboard or an assistive device. We will look at making platforms operable in the section on focus management.

Understandable : In this aspect, we consider the use of language which includes trying as much as possible to cut down spelling errors and complex grammar.

Robust : This means having consistency across the web. What this means is your platform must work the same way across all platforms.

Can React apps be made accessible?

We’ve heard this question a lot. The reason for this is that React applications rely on what is called a virtual DOM which is built every time a part of the application has to re-render because of a change. Breaking down components only accept a single root element (mostly a div) this is not semantic and will not be recognized by an accessibility tool like a screen reader.

However, accessibility in React can be achieved in a number of ways that will be discussed in this article.

Accessibility in React JSX

To achieve semantic JSX, there are a few tools and practices that can help to make your React application more user-friendly. We’ll be looking at these tools and practices in this section.

Before React Fragments

Before we take a comprehensive look at why React Fragments is important in making React accessible, let’s understand how semantic JSX was achieved before React Fragments in order to appreciate its importance.

1. Importing elements using Div tag

Normally when learning to build React applications we learn to wrap code for a particular component in a div or span tag. Most React developers use the div tag to ensure the code gets to its imported location as a block. Now, all this does is return a div inside another div, and this prevents writing semantic JSX.

Drawbacks of this method

When handling importations like this, what we are doing is building React’s Virtual Dom with div tags that would eventually be rendered to the main DOM as non-semantic HTML which makes it difficult for screen readers to interpret.

2. Using array as entry points

Since React components only return a single root element into another parent component, we can decide to map out the information in the child component to the parent component by returning an array of values like so:

import React from 'react'
    function NameList() {
     return (
      [
       <h2 key="1"> List of Developers in Nigeria </h2>,
       <li key="2"> Obinna </li>
       <li key="3"> Kofo </li>
       <li key="4"> Jola </li>
      ]
     )
    }
    export default NameList
Enter fullscreen mode Exit fullscreen mode

This works, although it leads to rendering extra elements in the DOM which might not be needed. Also having to always map out an array of elements that would have unique keys can be seen as a lot of syntax usage.

Using React Fragment

To solve the problem of unnecessary importations, a solution was introduced in React v16.8. Fragments helps you group a list of children without adding extra nodes to the DOM. Basically what fragments does is helps to guaranty a more semantic importation of child components to parent components by creating the virtual DOM exactly as we write it.

For instance, a simple use case would be calling a <td> (table data) tag in a <tr> (table roll) using old syntax:

class Table extends React.Component {
  render() {
    return (
      <table>
        <tr>
          <Columns />
        </tr>
      </table>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

In the columns component, we would have this:

class Columns extends React.Component {
  render() {
    return (
      <div>
        <td>Hello</td>
        <td>World</td>
      </div>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

But to avoid invalid HTML errors, the <Columns /> would need to return multiple <td> elements instead of a div when rendered. The output of the above would look like this:

<table>
  <tr>
    <div>
      <td>Hello</td>
      <td>World</td>
    </div>
  </tr>
</table>
Enter fullscreen mode Exit fullscreen mode

With fragments, this is solved like so:

class Columns extends React.Component {
  render() {
    return (
      <React.Fragment>
        <td>Hello</td>
        <td>World</td>
      </React.Fragment>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Fragments can be used like this <React.Fragment> or by using empty tags <>.

Things to note when using Fragments

  • When using empty tags, it doesn’t support using keys for mapping out data
  • Keys are the only attributes supported by the <React.Fragment> tag for now

How does this help write semantic JSX?

The obvious way React Fragments helps to improve semantic JSX is by eliminating unnecessary div tags in the DOM tree, it also allows us to write more semantic HTML which, as stated earlier, is the bases of accessible code. Other tips to achieving accessibility include:

  • Changing a div to an article/section can make a huge difference
  • Use h1 – h6 for anything that is a header to notify screen readers about the page sections
  • Use links for navigation
  • Handle all On-click functions with a button
  • If an element is off-screen, ensure that its visibility is set to hidden
  • Making good use of ARIA which helps to add a semantic behavior to an element that isn’t implicitly semantic E.g. A sidebar should use aria-expand to let screen readers know
  • Labeling buttons to give additional information on what the button does

Focus & focus management

Focus refers to the control from the computer screen that receives input when you send information, this is usually associated with the keyboard. Whenever you attempt to fill a form or use a specific part of a web page, you have to put it in focus. Now, this is important to users who would rather navigate the platform with the keyboard using tab and shift keys or have some sort of motor disability.

Focus management:

Well planned focus management is important in ensuring a comfortable user experience. What this means is moving the cursor from one part of the app to another. In order to help users (mostly with motor disabilities) navigating the platform with the keyboard in the intended flow of the app. Some elements are implicitly focus-able such as form elements, anchor elements while others are not (such as p, h2 tags).

Achieving focus management in React using ref

In order to focus an element using React we create a function Ref, which is a prop that is set on the element we want to reference, it allows us to select and reference an actual DOM node on the page in React.

<div
  ref ={
    (loadingNames)=> {
        this.loadingNames = loadingNames;
    }
  }
  tabIndex = "-1"
>
Loading List of Names...
</div>
Enter fullscreen mode Exit fullscreen mode

The above code assigns the ref of the div to the class property this.loadingNames to implement a ref we use the componentDidMount life cycle, then call the focus element of the ref element like this:

componentDidMount(){
    this.loadingNames.focus()
    }
Enter fullscreen mode Exit fullscreen mode

So what this does is, when the list of names loads, the keyboard focus indicator will put a focus ring on the content.

Another use case for using ref would be making sure that we shift focus to the new page when using react-router, by calling a ref for the top of the page and causing the user to navigate from the top of the new page the <link> connects to.

<div
ref={
  (topOfNewPage)=>{
    this.topOfNewPage = topOfNewPage;
  }
}
 tabIndex = "-1"
 aria-labelledby = "pageHeading"
>
  <Header / >
    <h1 id ="pageHeading"> </h1>
   <Footer/>
</div>
Enter fullscreen mode Exit fullscreen mode

Using the ref like so:

componentDidMount(){
this.topOfNewPage.focus()
}
Enter fullscreen mode Exit fullscreen mode

With the release of React v16.8 there is a way to write refs using React.createRef() API. You can find more information in the official documentation.

Other helpful tips when implementing semantic JSX

1. Setting page titles using componentDidMount

This helps to increase SEO, and also can update the content in the browser tab, it also enables screen readers to have a better understanding of their current place in the application.

componentDidMount(){
    document.title = 'Input your page title '
    }
Enter fullscreen mode Exit fullscreen mode

Other ways to do this is by using packages like react-document-title and react-helmet which can be installed to the project via NPM.

2. React accessibility linter (eslint-plugin-jsx-a11y)

Using a linter helps to determine clean code by checking code written by code standards determined by a team or by an individual. Using the eslint-plugin-jsx-a11y linter we can set up a more accessible react app. You can also configure this to work with your text-editor so as to get real-time error outputs. It can also be installed using NPM.

npm install eslint esline-plugin-jsx-a11y --save-dev
Enter fullscreen mode Exit fullscreen mode

3. Writing semantic HTML

Mostly writing code that is semantic can go a long way in aiding a more accessible platform, earlier in the article I stated ways to achieve this. Also referring to this guide can help with this.

Conclusion

In this article, we have attempted to understand the basics of accessibility for the web as it applies to React applications and also looked at some accessibility principles in general. I hope we put these practices into play when building React applications to enable a better web for everyone. Happy Coding! 😄


Editor's note: Seeing something wrong with this post? You can find the correct version here.

Plug: LogRocket, a DVR for web apps

 
LogRocket Dashboard Free Trial Banner
 
LogRocket is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
 
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
 
Try it for free.


The post The state of semantic JSX appeared first on LogRocket Blog.

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.