Updating your existing apps for accessibility
Tags: a11y, react, vue, javscript
Published: 2019-12-02 14:45:50

---
title: Updating your existing apps for accessibility
published: true
date: 2019-11-28 17:00:26 UTC
tags: accessibility,react,vue,javscript
canonical_url: https://blog.logrocket.com/updating-your-existing-apps-for-accessibility/
cover_image: https://thepracticaldev.s3.amazonaws.com/i/unecx8dlc03delj7jxae.png
---
**Written by [Raphael Ugwu](https://blog.logrocket.com/author/raphaelugwu/)**✏️

The web has an ever-growing user base, and more activities than ever are centered around web applications. It’s important for developers and product managers to build interfaces that are applicable to not only a lot of use cases, but a wide range of abilities as well. The [World Wide Web Consortium (W3C)](https://www.w3.org/WAI/standards-guidelines/wcag/) created a set of specifications to show how web apps can be made accessible to individuals who may face challenges when using them. This includes people with physical, visual, speech, auditory, and intellectual impairments.

JavaScript is arguably the most popular language used to build web apps, and its two most popular frameworks are [React](https://github.com/facebook/react) and [Vue](https://github.com/vuejs/vue). Let’s take a look at how we can make web apps built with either framework more accessible to users with limitations.

[![LogRocket Free Trial Banner](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/f760c-1gpjapknnuyhu8esa3z0jga.png?resize=1200%2C280&ssl=1)](https://logrocket.com/signup/)

## Improving markup with ARIA Attributes

Accessible Rich Internet Applications (ARIA) attributes are huge part of accessibility in web apps. You can use them to specify attributes that define the way an element is translated into the [accessibility tree](https://developers.google.com/web/fundamentals/accessibility/semantics-builtin/the-accessibility-tree).

To demonstrate how ARIA attributes can be used to improve accessibility in React apps, let’s say we have an e-commerce app and we want to make the checkout process easy.

```jsx
render() {
  return (
      <div>
        <h3>"Click below to use Prime's lifetime access at $10.99 per month"</h3>
        <button onClick={this.makePayment}>Pay Here</button>
      </div>
    );
  }
}

render(<Payment />, document.getElementById("root"));
```

Here’s the problem: if a [screen reader](https://accessibility.its.uconn.edu/2018/08/22/what-is-a-screen-reader-and-how-does-it-work/#) is being used on this web app, it might detect the button but not the text in the `<h3>` tag. As a result, a visually impaired user who doesn’t detect this might unknowingly sign up for a service where they’ll be deducted every other month. We can use an ARIA attribute to make this more accessible.

```jsx
render() {
    return (
      <div>
        <h3> Click below to use Prime's lifetime access at $10.99 per month </h3>
        <button
          onClick={this.makePayment}
          aria-label="Click below to use Prime's lifetime access at $10.99 per month"
        >
          Pay Here
        </button>
      </div>
    );
  }
```

In the code sample above, `aria-label` tells the app’s users what exactly the button pays for. But what if the text in the `<h3>` tag is really long? We wouldn’t want to fit in an entire paragraph in `aria-label`. Let’s modify our `return` statement to include another ARIA attribute:

```jsx
render() {
    return (
      <div>
        <h3 id="lifetimeAccess">
          Click below to use Prime's lifetime access at $10.99 per month
        </h3>
        <button 
          onClick={this.makePayment} 
          aria-labelledby="lifetimeAccess"
        >
          Pay Here
        </button>
      </div>
    );
  }
```

With the `aria-labelledby` attribute, a screen reader can detect that the element with the `id` of lifetime access is the button’s label.

With Vue, this is almost the same thing except for changes in syntax:

```jsx
<template>
  <div>
    <h3 :id="`lifetimeAccess`">
      Click below to use Prime's lifetime access at $10.99 per month
    </h3>
    <button 
      @click="makePayment()" 
      :aria-labelledby="`lifetimeAccess`"
    >
      Pay Here
    </button>
  </div>
</template>
```

## Managing Focus

It’s important to give users options for how to handle focus when accessing your app. Keyboard focus is a good option because it allows people who have limited mobility in their wrists to access your app easily. Vue implements keyboard focus through the use of [custom directives](https://vuejs.org/v2/guide/custom-directive.html).

```jsx
<template>
  <div id="app">
    <div v-if="flow == 'search'">
      <input type="text" placeholder="Enter your query" v-model="search" v-focus>
      <button>Search</button>
    </div>
  </div>
</template>

<script>
import Vue from "vue";

Vue.directive("focus", {
  inserted: function(el) {
    el.focus();
  },
  update: function(el) {
    Vue.nextTick(function() {
      el.focus();
    });
  }
});

export default {
  name: "App",
  data() {
    return {
      flow: "search",
      search: null
    };
  }
};
</script>
```

In the code sample above, `v-focus` is registered globally as a custom directive. It is then inserted into the DOM and wrapped in a `nextTick`. This will [hold the focus event until the DOM is updated](https://vuejs.org/v2/api/#Vue-nextTick) and the input is displayed.

{% youtube IpdlakY6Wjg %}

As shown in the short clip above, the focused element is the one currently receiving input. React accomplishes the same thing with `refs`. You can [use refs to access DOM nodes or React elements](https://reactjs.org/docs/refs-and-the-dom.html) created in the `render` method.

Here we’ll create a ref for the component to which we want to add an element and then update the focus using the `componentDidMount` lifecycle method:

```jsx
import React, { Component } from "react";
import { render } from "react-dom";

class App extends Component {
  constructor(props) {
    super(props);
    this.focusDiv = React.createRef();
  }
  componentDidMount() {
    this.focusDiv.current.focus();
  }
  render() {
    return (
      <div className="app">
        <input tabIndex="-1" ref={this.focusDiv} placeholder="Enter your query" />
        <button>Search</button>
      </div>
    );
  }
}
render(<App />, document.getElementById("root"));
```

The `tabIndex` value is set to `-1` to allow you to set programmatic focus on an element that is not natively focusable. When configuring keyboard focus, do not add CSS styles that remove the outline or border of elements, since these could affect the outline that appears when an element is in focus.

## Accessibility in route transitions

Screen readers have certain limitations with navigating routes in single-page apps built with React or Vue. During navigation, the routing software of these frameworks handles some of the navigation actions from the browser to prevent constant reloading of the host HTML page.

Screen readers depend on the browser to feed them updates on navigation, but since this functionality is being handled by frameworks, what follows is a totally silent page transition for visually challenged users. Other examples are error situations and content and state changes in our application that could be very clear visually but go undetected by screen readers.

`react-aria-live` is a React library that uses [ARIA live regions](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions) to announce route changes in an application. Suppose we want a visually impaired user to know that the `Order` page in an e-commerce app has loaded:

```jsx
import React, { Component } from "react";
import { LiveAnnouncer, LiveMessage } from "react-aria-live";

class App extends Component {
  state = {
    message: ""
  };
  componentDidMount() {
    document.title = "Orders Page";
    setTimeout(() => {
      this.setState({ message: "The Orders page has loaded" });
    }, 3000);
  }
  render() {
    return (
      <LiveAnnouncer>
        <h1 tabIndex="-1"> Confirm your orders here</h1>
        <LiveMessage message={this.state.message} aria-live="polite" />
        ); }
      </LiveAnnouncer>
    );
  }
}

export default App;
```

In the code sample above, `LiveAnnouncer` wraps the entire app and renders a visually hidden message area that can broadcast `aria-live` messages. The `LiveMessage` component does not have to exist in the same component as `LiveAnnouncer`; as long as it exists inside a component tree wrapped by `LiveAnnouncer` , it is used to convey the message using either an `assertive` or `polite` tone.

Vue informs screen readers of route changes with `vue-announcer`, a library similar to `react-aria-live`. Here you may also have to manually configure messages. Let’s replicate the same `Orders` page, only this time using Vue:

```jsx
<template>
  <div id="app">
    <h1 tabindex="-1">Confirm your orders here</h1>
  </div>
</template>
<script>
export default {
  name: "App",
  head: {
    title: {
      inner: "Orders Page"
    }
  },
  methods: {
    mounted() {
      setTimeout(() => {
        let message = `The Orders page has loaded`;
        this.$announcer.set(message);
      }, 3000);
    }
  }
};
</script>
```

In the code sample above, `this.$announcer` notifies the user by sending an auditory message three seconds after the page has loaded.

## Summary

A huge first step toward [achieving accessibility](https://www.netlify.com/blog/2019/02/25/accessibility-is-not-a-react-problem/) is acknowledging that there are people out there who do not use your apps and devices in a conventional manner. Building apps that address their needs can help increase user retention and demonstrate your commitment to inclusiveness.

* * * 
**Editor's note:** Seeing something wrong with this post? You can find the correct version [here](https://blog.logrocket.com/updating-your-existing-apps-for-accessibility/).

## Plug: [LogRocket](https://logrocket.com/signup/), a DVR for web apps
 
![LogRocket Dashboard Free Trial Banner](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png?resize=1200%2C677&ssl=1)
 
[LogRocket](https://logrocket.com/signup/) 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](https://logrocket.com/signup/).
* * *
The post [Updating your existing apps for accessibility](https://blog.logrocket.com/updating-your-existing-apps-for-accessibility/) appeared first on [LogRocket Blog](https://blog.logrocket.com).