Laura Carballo Frontend developer with a strong interest in design systems and web accessibility.

Testing accessibility with Storybook

4 min read 1165

Testing accessibility with Storybook

One big challenge when building a component library is prioritizing accessibility. Accessibility is usually seen as one of those “nice-to-have” features, and unfortunately, we’re still far from considering it an essential part of a developer’s skill set.

I get it — introducing accessibility practices can be challenging and time-consuming. But there are amazing tools that can help you and your team make that implementation less overwhelming and, more importantly, make it last.

In this article, we’ll be exploring Storybook’s accessibility add-on in the following sections:

  • How to install and configure the add-on
  • Using the accessibility add-on to test a Navigation component
  • Walk through some common accessibility issues that can be easily audited with the help of Storybook

Why Storybook?

Storybook is broadly used across teams to develop a consistent UI. This open source project brings design and engineering teams together to focus on organizing a perfect component library.

With the help of multiple contributors, Storybook’s team has been developing new add-ons that extend additional features to their core UI. In their effort to help users build accessible applications, Storybook released their accessibility add-on.

The idea behind this project is to provide support for automated accessibility tests within Storybook to capture and surface accessibility errors. Solving these issues throughout the development process allows us to spend more time on manual testing with assistive technologies and, consequently, to raise accessibility standards throughout the web.

The accessibility add-on runs the deque axe accessibility testing tool on each Story. axe is an automated accessibility testing tool that can be used with your framework or browser of choice.

The accessibility add-on provides a panel in which we can visualize axe’s test results within each Story’s UI. This is pretty great because we can test our component’s adherence to common accessibility standards and guidelines within the developing process.

On top of that, the accessibility add-on includes a color blindness simulator that replicates visual impairments such as deuteranomaly, protanomaly, or tritanopia.
The color blindness simulator menu

Adding the accessibility add-on to your project

Before installing Storybook, it is important to keep in mind that it cannot be run in an empty project. Storybook needs to check your project’s dependencies to provide you with the best configuration. In our case, we’ll run it in a React application.

We made a custom demo for .
No really. Click here to check it out.

For this reason, we’ll run Create React App first to initialize our React application. If you have a desired project in mind, you can simply install Storybook:

# Add Storybook:
npx sb init


# Starts Storybook in development mode
npm run storybook

Storybook already comes with some essential addons, but unfortunately, these do not include the accessibility add-on, so we’ll have to install it as well:

npm install @storybook/addon-a11y

To conclude with the set up, we’ll need to create or add a main.js file inside the .storybook folder with the following:

// .storybook/main.js
module.exports = {
  addons: ['@storybook/addon-a11y'],
};

Testing our component

Let’s have a look at an example of a top navigation component.

The top navigation component of our demo app

 

At first glance, the component looks ready to ship, but if we go into the accessibility tab, the tests tell us something different.

The axe accessibility readout of our top navigation component

The navigation component is missing certain accessibility requirements, so axe enumerates four violations.

The accessibility add-on comes with a Highlight results checkbox that helps identify the components that are failing. This can be very useful when dealing with bigger components because it will save us from having to rerun these tests individually in each component.

  • Ensure buttons have discernible text — indicates that when using icons as buttons without a visible label, it is important to add an inner text for screen readers, which can be done by adding an aria-label
    • Our contrast ratio doesn’t meet the WCAG AA ratio thresholds, which makes our links and text hard to read across the component
  • Our Navbar includes an avatar with an image that does not have an alt attribute for alternate text descriptions
  • Ensure <li> elements are used semantically — detects that the list elements that are being used as links are not wrapped in a <ul> element. Using semantic HTML is highly recommended because it allows screen readers and assistive technology users to easily navigate across the page’s heading and sections

As I mentioned earlier, the accessibility add-on detects all of these accessibility violations fairly quickly, which makes it great for maintaining a high focus on core accessibility standards at an early stage of the development process.

Configure axe to your needs

It is worth mentioning that the accessibility add-on respects axe’s rule-based system and allows us to configure the accessibility violations depending on our needs.

For a better understanding of the set of rules that you can override and disable, check the axe-core configurationOptions. If you’re not too familiar with axe, I highly recommend going through the rule description — it will give you insight into what rules can be customized and provide you with further research on the best scenarios in which to do so.

For example, we can override some of these rules on the Story level using parameters.a11y.config.rules:

const Story = {
 title: "Components/Navigation",
 component: Nav,
 parameters: {
   a11y: {
     config: {
       rules: [
         {
    //  Override the result of a rule to return "Needs Review" rather 
    //  than "Violation" if the rule fails. It will show in the
    //  'Incomplete' tab.
           id: "color-contrast",
           reviewOnFail: true,
          },
        ],
      },
    },
  },
};

If we want to ignore a rule at a global level, we can use parameters.a11y.config.rules in our Storybook’s preview.js file:

// .storybook/preview.js
export const parameters = {
  a11y: {
    config: {
      rules: [
        {
          id: 'listItem',
          enable: false,
        },
      ],
    },
  },
};

It is always advisable to include a comment with the reason why a rule was overridden, as it will help you and your team understand why some rules aren’t being reported during testing.

Automating accessibility tests

It is possible to use Storybook in automated tests, and it supports integrating your stories with testing frameworks like Jest. Furthermore, you can also use React Testing Library, too. Or, you can use both.

On top of this, we can also implement accessibility tests on each of our components with the Jest Axe integration. This project introduces an axe-matcher into Jest so that you can automate the search for violations.

const { axe, toHaveNoViolations } = require('jest-axe');

expect.extend(toHaveNoViolations);

/// tests

Conclusion

A final note: other accessibility practices, like testing UI against the most common assistive technologies and including disabilities within your user research, are still highly encouraged methods of testing the accessibility of your apps. This is just one way to surface accessibility issues within your app, and by no means a replacement for the manual tests we described.

It is very exciting to see how there is an increasing effort to introduce developer tools that contribute to building accessible UI. Even though adding test coverage does not ensure your component library is fully accessible, it is certainly a step toward acknowledging accessibility as a standard for a perfect component library.

: Full visibility into your web apps

LogRocket is a frontend application monitoring solution 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.

Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — .

.
Laura Carballo Frontend developer with a strong interest in design systems and web accessibility.

Leave a Reply