Accessibility-flavored React components make your design system delicious! Kathleen McMahon — O’Reilly Media

Welcome everyone! I’m Kathleen McMahon and I’m here today to talk about how you can flavor your React components with accessibility seasonings to make your design system delicious!

I’m going to cover this a bit quickly, so let’s get some details out of the way

My slide deck will be posted here after my talk https://noti.st/resource11/MZsVDq

And here are my social links

@resource11 Twitter | Instagram | GitHub @cxsisters Instagram

Now… here’s an outline of what we’ll be covering today.

Good grief, there’s an agenda…

• Why accessible components?

• Design systems are a cookbook

• Design systems and React

• Icons

• Buttons

• Inputs

• Documentation

Let’s back up so I can introduce myself better…

I’m the Tech Lead for O’Reilly Media’s Design System

And I race bikes… very badly.

I try to get more women racing bikes and run the CXsisters social media campaign

But mostly, you’ll find me at the back of the pack, racing 2 laps to your 6 on a singlespeed, wearing a costume!

Because who doesn’t love a clown?

Well maybe not this clown…

One thing I almost forgot to mention…

I’m a dev dinosaur. I remember when…

…computers looked like this and…

…software looked…

…like this.

And we stored stuff on this…

…and looked things up like this.

This browser was the newest hotness…

…and this was our stack. HTML, CSS, and JavaScript.

Fast forward to now and the industry is moving at a really fast pace and…

…you need to adapt quickly to keep up. That can get a bit overwhelming, and you can start feeling…

…like panicky Natalie Portman sobbing in the corner. And that’s natural. Because we all want to stay relevant. But fear not!

Dinosaurs are always the hotness.

Those old-school HTML/CSS/JavaScript skills are highly valuable and transferrable, no matter which framework you use.

They give you an edge in the industry where the div has become the reluctant king.

Thank you for coming to my talk. Kidding. Let’s dig in further.

Why accessible components? And also…

Why should we care?

Our users are varied and they access our pages in many ways.

…depending on ability, preference, and the circumstance.

Here’s a short list of technologies • Desktop, Mobile device, Trackpad, Mouse • Keyboards: standard, braille, morse code • Straw device, switch control • Screen readers, Magnification software, voice assistants

The W3 has developed a set of guidelines to help us make our apps accessible: they’re called the Web Content Accessibility Guidelines or WCAG for short.

There are three levels of conformance. A, AA, AAA, and, WCAG 2.1 level AA is the gold standard for inclusive apps, AAA is the holy grail

There are four principles of accessibility to follow. Those are:

Perceivable Information and UI components must be presentable to users in ways they can perceive.

Operable UI components and navigation must be operable.

Understandable Information and the operation of user interface must be understandable.

Robust Content must be robust enough that it can be interpreted reliably by a wide variety of user agents, including assistive technologies.

The easiest way to remember these principles is to POUR yourself some coffee.

Or perhaps some espresso? Because we’re in Milan, after all…

Now we have the standards and principles to follow

We don’t want to leave users behind, and yet…

In February 2019, WebAIM conducted an accessibility analysis top 1,000,000 home pages and the results were pretty depressing.

97.8% of home pages had detectable WCAG 2 failures.

59% of 3.4 million form inputs were unlabeled

60.1% of the 1 million pages had unnecessary ARIA attributes present

Of those pages, there were 26.7 more detectable errors on average than home pages without ARIA.

6 months later…

In August 2019, WebAIM conducted a re-analysis of those same 1,000,000 home pages. Think things got better? Well…

The amount of ARIA on the pages…

…increased, from 60.1% to 64.5%.

Yikes. While developers had good intentions, they actually made the accessibility of those pages worse because they’re implementing things incorrectly.

Imagine, though, if you had accessibility baked into some commonly-used components.

Wouldn’t that be cool? What if that was in your design system?

What is a design system, anyway?

There’s a great inVision blog post that I’ll paraphrase: A design system is a collection of reusable components, guided by clear standards, that can be assembled together to build any number of applications.

An now for the hot take of the day:

Great design systems combine team AND consumer experience.

So often you hear about focusing on developer experience when creating a tool.

More often than not, the most important goal of the design system gets lost in that process: the end user experience.

We need to remember the original purpose of the system: to create a great consumer experience. I mean, what good is it if your system is great for developers. yet the end product isn’t usable?

I like to say your design system is a cookbook.

And cookbooks have personality. My Mom is a serious fan of cooking, and lately I’ve been enjoying digging through the cookbooks she’s collected over the years to read how recipes evolved over time.

If you’ take a look at some of the cookbooks published in the 1940s-60s…

…and look past the outdated views…

…you’ll find interesting recipes…

…questionable food combinations that included Jello and meat…

…and an impressive level of detail paid to the structure of every single part of the cooking process. This is very similar to how a design system works.

Now what does that have to do with React?

There’s always some debate about how using a Javascript framework creates inaccessible apps

Yet… React fully supports building accessible websites, by using standard HTML/CSS techniques.

A better way to think of React is to consider it a kitchen utensil. It’s not the only utensil in your kitchen.

You are the cook. In my opinion, It’s up to the developer to have that standard HTML/CSS/JavaScript and accessibility knowledge to be able to leverage a utensil correctly. And that includes React.

That said, if your developers are unsure how to start building inclusive apps, empower with your design system. Build some features into your components to help them along.

Components are your tried and true recipes

WCAG is Your reference material

Creating a component is like following a recipe.

First, you start off with high-quality ingredients, semantic HTML…

…mix in seasonings, just a touch of ARIA…

…follow the directions, your documentation…

…and provide helpful hints as best practices.

Let’s talk icons. Icons are a great way to add a bit of flourish to your product. They’re used to supplement key messaging and call attention to areas of importance.

Icons can be informative or decorative. Informative icons need alternative text to be perceivable by assistive technology. Decorative icons don’t add significant value, need to be hidden from assistive technology.

There is more than one way to create an accessible icon. Two of the most recent are… SVGs and icon fonts. You’ll hear that SVGs are the new hotness for accessible icons, and it’s true! In fact, we initially used SVG icons combined into a sprite sheet until…

…we discovered a VoiceOver bug when testing on High Sierra, which brought out my Natalie Portman sobbing in the corner. As a temporary solution…

We converted all our icons into a font set and use that instead. Let’s go over an example of how we make an accessible icon component using semantic HTML and the icon font technique.

This is what you typically see as an icon font element in the wild, but it’s not accessible.

This is an accessible icon pattern. Let’s break it down.

We begin with a span element and use a CSS class to attach our icon font family with some baseline styling.

Then, we apply a separate class to the span and assign the icon we want to use as a pseudo-element. In this case, that’s the email icon.

Next, we add a second span with descriptive name for our icon.

Then, we’ll add a wrapping span around the spans and use CSS class to convert the span’s native display property from inline to inline-block. This supports margin/padding customization on all four sides of the element.

Next, we’ll add the visuallyHidden class to the span containing descriptive text. This will remove the visual presentation of that text, yet keep that text available to screen readers.

This is a high quality component… but.

Even though this markup uses high-quality ingredients, when read by a screen reader, this will announce: “\f12f email”. That’s not an ideal situation. It’s time to mix in some key accessibility spices.

We’ll sprinkle a pinch of aria-hidden=”true” to the span containing the icon font

makes sure the unicode characters won’t read out to a screen reader.

Before we refactor this pattern into a React component, let’s consider whether this component is informative or decorative?

If our icon is informative, we keep this markup as is, because informative icons should announce.

If our icon is decorative, we’d add this aria-hidden attribute to the wrapping span to ensure the entire group is not announced to a screen reader.

Now that we have an accessible icon pattern, let’s convert this to JSX.

The class is now changed to className, we convert the aira-hidden prop from a string to a boolean, and because there’s no text inside that first span, we close the JSX element.

Let’s make this component more flexible.

Since our components handle presentational logic only, we’ll expand that syntax to support incoming props, such as:

• iconHidden for controlling how icon announces

• iconName for passing in the icon we want to use

• iconTitle for passing in descriptive text for the icon

Guardrails

It’s important to create ‘guardrails’ for your components so you can be sure that devs are always using the accessibility features you’ve mixed in.

The first guardrail we’ve set up is a check if the iconName the dev passes in to the component is in our icon library. If the icon doesn’t exist in the library, the component doesn’t render in the app.

The second guardrail we’ve set here is to ensure the icon’s default name is always exposed, unless the dev passes in a custom text value.

The last guardrail is the iconHidden prop. If the dev passes in iconHidden true, the containing span’s will render with an aria-hidden=”true” attribute.

If no iconHidden prop is passed in, the aria-hidden attribute isn’t added to the wrapping span at all.

This way, we’re guaranteeing that the icon will read out to screen readers no matter what, unless the dev purposely specifies otherwise by passing in iconHidden value

We’re also ensuring that this boolean attribute is attached to the component only if it’s true. There are certain boolean attributes in HTML that need a true or null pattern, and aria-hidden is one of them.

Let’s talk buttons

• Buttons perform an action on the page.

• Buttons should look and act like a button.

• Use semantic HTML, get screen reader and keyboard functionality for free.

First, we start with the high quality ingredient: the button element.

Our designer has provided a button look and feel that has proper color contrast of text and button borders against the background.

We’ve made sure that we’re leveraging the hover, focus, active and disabled pseudo classes to inform users when they can interact or not with this button.

We also have an aria-label added here to support instances where we have multiple buttons with the same name on the page, as a result of data we’re receiving from an API that didn’t provide distinct button test. This way, we can give context to screen reader users who otherwise wouldn’t know the purpose of that button.

This is an accessible button in HTML.

Let’s convert this button syntax to JSX.

If we want to support button text with icons, we mix in our Icon component.

A span element wraps the Icon and the button contents to leverage flexbox display properties. This is needed to properly position text and icon in cross-browser applications.

Also, use inline not block elements inside buttons, and no nesting buttons or other controls inside a button’s children. That’s not valid HTML.

The JSX is popped into the Component’s render method, and we add props support.

We also need to add onClick handler support, and a prop to set the button’s attribute to disabled if needed is sprinkled in as well.

Lastly, we add a guardrail to ensure if no iconName is passed in, no icon will render in the button.

Inputs

Inputs need labels and error messages. Labeled inputs give all users more context.

• Placeholders are NOT labels.

• Avoid using placeholders instead of labels, users will lose context.

• They’re hard to style across browsers.

• Placeholders aren’t auto translated.

Smashing Magazine published a great article about this written by Eric Bailey.

We’ve built our input components to minimize horizontal scrolling.

• Max input width: 80 characters.

• Keep labels stacked vertically.

• Labels above input, errors below input.

This is an accessible Input component in JSX. This is a bit hard to read on the screen, so let’s zoom in a bit.

Start with high-quality ingredients, semantic HTML.

Inputs need labels and error messages.

For and id to associate label with input.

Mix in key spices (ARIA … not too much) for validation. Add aria-required, aria-describedby, aria-invalid, and error id.

Allow screen readers to receive the input’s error context by adding aria-live attribute of polite.

Convert syntax to JSX.

Sprinkle on the onChange and OnKeypress synthetic event support to capture keyboard actions. Add true/null handling for the boolean props.

Add your guardrails. If the dev doesn’t pass in a label, the whole input won’t render. Neither will the icon. This will help guide the developer to follow best practices when implementing a component.

Same goes for the error handling, if the developer doesn’t pass in both the invalid prop and the error message prop to the component, it won’t render.

Document, document, document

• Make your documentation expansive.

• Be sure to add examples of the many ways a component can be used.

• Also, make it straightforward to contribute to your codebase.

Our Design System uses Gatsby and Storybook to document our components and we host static instances on Zeit’s Now.

[demo of Gatsby site]

I want to touch upon Storybook for a moment.

• Storybook is a great way to Sandbox your components in isolation.

• Play with UI logic without the nonsense of business logic.

• Accessibility addon is a must.

Accessibility addon uses axe-core engine, does the heavy lifting. Identifies low-hanging fruit errors to fix.

Add helpful hints.

Helpful hints Decorative Icon.

Prop tables.

Provide component dos and don’ts.

Also, dedicate a page to accessibility resources and links.

Wrap-up

Our users are diverse

Your Design system is a cookbook

Cookbooks have Personality

React is a kitchen utensil

You are the cook

Components are your tried and true recipes

Helpful hints in every recipe

WCAG is Your reference material

Document, document, document. And…

…Dinosaurs are ALWAYS the hotness

Thank you.

@resource11 Twitter | Instagram | GitHub @cxsisters Instagram