Creating Accessible React Apps

Can React apps be accessible? πŸ€”

Yes! πŸ˜„πŸ™ŒπŸš€πŸ•

(Continue on to find out how.)

Agenda βœ…

  1. A few notes on starting with React
  2. Setting the page <title>
  3. Live announcements
  4. Focus management
  5. React's accessibility linter
  6. Writing semantic HTML in React
  7. Demo! (time permitting)

A few notes on starting with React πŸ““

camelCase

Write attributes in camelCase πŸͺ

  • tabindex πŸ‘‰ tabIndex
  • contenteditable πŸ‘‰ contentEditable
  • maxlength πŸ‘‰ maxLength

(aria-* and data-* are exempt from this.)

Reserved words

When HTML conflicts with JS πŸ˜•

  • for πŸ‘‰ htmlFor
  • class πŸ‘‰ className

Self closing tags require /

What is this, XHTML? πŸ€·β€

  • <img src="…" alt=""> πŸ‘‰ <img src="…" alt="" />
  • <meta charset="utf-8"> πŸ‘‰ <meta charset="utf-8" />
  • <input type="text"> πŸ‘‰ <input type="text" />

Setting the page <title> πŸ—‚

Why bother? πŸ€”

  • Updates the browser tab
  • SEO
  • Often the first content announced by screen readers

Use document.title

            
              componentDidMount() {
                document.title = 'My page title';
              }
            
          

Other existing components

  • react-document-title
                    
                      <DocumentTitle title='My page title'>
                        <!-- content -->
                      </DocumentTitle>
                    
                  
  • react-helmet
                    
                      <Helmet>
                        <meta charSet='utf-8' />
                        <title>My page title</title>
                        <link rel='stylesheet' href='css/page-specific.css' />
                      </Helmet>
                    
                  

Live announcements πŸ“’

The Announcements component

            
                import React from 'react';

                class Announcements extends React.Component {
                  render() {
                    return (
                      <div aria-live="polite" aria-atomic="true" className="visuallyhidden">
                        {this.props.message}
                      </div>
                    );
                  }
                }

                export default Announcements;
            
          

Usage, part 1

Create a state property

            
              this.state = {
                message: null
              };
            
          

Usage, part 2

Set the state property

            
              this.setState({
                message: 'Some message'
              });
            
          

Usage, part 3

Send message to <Announcements /> component

            
              <Announcements message={this.state.message} />
            
          

Other existing components

  • react-aria-live
                    
                        <LiveAnnouncer>
                          <LiveMessage message={this.state.a11yMessage} aria-live="polite" />
                          <button onClick={() => {this.setState({ a11yMessage: 'Button Pressed' });}}>
                            Press me
                          </button>
                        </LiveAnnouncer>
                    
                  
  • react-a11y-announcer
    (Literally the same thing I described earlier)

Focus management πŸ”€

Selecting an element

Kind of like jQuery πŸ€·β€β™‚οΈ.

            
              var loadingMessage = $('#loadingMessage');
              // …
              loadingMessage.focus();
            
          

The React way

Use a function ref to reference the element elsewhere in the component.

            
              <div
                ref={
                  (loadingMessage) => {
                    this.loadingMessage = loadingMessage;
                  }
                }
                tabIndex='-1'
                >
                Loading…
              </div>
            
          

Using the ref…

            
              componentDidMount() {
                this.loadingMessage.focus();
              }
            
          

More focus management! πŸ“°

Why manage focus when loading a new page? πŸ€”

When using React Router's <Link /> component, the browser never reloads, leaving the user in an unknown position.

Our new friend, ref

            
              <div
                ref={
                  (contentContainer) => {
                    this.contentContainer = contentContainer;
                  }
                }
                tabIndex="-1"
                aria-labelledby="pageHeading"
                >
                  <Header />
                    <h1 id="pageHeading">…</h1>
                    // Content components…
                  <Footer />
              </div>
            
          

Set "page" focus via ref

            
              componentDidMount() {
                this.contentContainer.focus();
              }
            
          

React's accessibility linter πŸ›€

eslint-plugin-jsx-a11y

Outputs errors to the browser console automatically.

            
              <img src="images/chrome-console.png" />
            
          
Screen capture of Chrome's developer tools console. A warning message states, 'img elements must have an alt prop, either with meaningful text, or an empty string for decorative images.'

Code editor a11y linting? πŸ€”

Let's output errors directly in the editor, too.

Screen capture of Atom text editor. A warning message appears overtop of some code with the following message, 'img elements must have an alt prop, either with meaningful text, or an empty string for decorative images.'

1. Install ESLint Plugin

2. Install ESLint && eslint-plugin-jsx-a11y

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

3. Update the .eslintrc file

Add to the "plugins" section:

            
              "plugins": [
                "jsx-a11y"
              ]
            
          

Add to the "extends" section:

            
              "extends": [
                "plugin:jsx-a11y/recommended"
              ]
            
          

Writing semantic HTML in React ✍️

React Components are ES6 Classes

Since React uses ES6 classes to make up its components, it’s up to you to continue to write good, clean, semantic HTML.

In other words…

If there are accessibility issues, it's your fault. This is a good thing! πŸ‘

Demo! πŸ“±

Thanks! πŸ™‚