Continue on to find out how…
titleReact.Fragment
Write attributes in camelCase 🐪
tabindex 👉 tabIndexcontenteditable 👉 contentEditablemaxlength 👉 maxLength(aria-* and data-* are exempt from this.)
When HTML conflicts with JS 😕
for 👉 htmlForclass 👉 className/<img src="…" alt=""> 👉 <img src="…" alt="" /><meta charset="utf-8"> 👉 <meta charset="utf-8" /><input type="text"> 👉 <input type="text" />title 📰
When someone using a screen reader loads a new page, the initial page announcement is always the same.
title! 👍document.title
componentDidMount() {
document.title = 'My page title';
}
<DocumentTitle title='My page title'>
<!-- content -->
</DocumentTitle>
<Helmet>
<meta charSet='utf-8' />
<title>My page title</title>
<link rel='stylesheet' href='css/page-specific.css' />
</Helmet>
When a Single Page App fetches data, the new content is visibly displayed.
However, screen reader users recieve no indication of the available content.
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;
Create a state property
this.state = {
message: null
};
Set the state property
this.setState({
message: 'Some message about the current state'
});
Send message to <Announcements /> component
<Announcements message={this.state.message} />
<LiveAnnouncer>
<LiveMessage message={this.state.a11yMessage} aria-live="polite" />
<button onClick={() => {this.setState({ a11yMessage: 'Button Pressed' });}}>
Press me
</button>
</LiveAnnouncer>
A loading screen in our app displays a message in-between fetching new data. Sighted users can read the message a wait patiently… probably.
However, screen reader users do not recieve this message conveying the current app state. They might get discouraged or blame themselves when something takes a long time to load.
Let's shift focus to the Loading message container when it gets displayed.
Kind of like jQuery. 🤷♂️
var loadingMessage = $('#loadingMessage');
// …
loadingMessage.focus();
Use a function ref to reference the element elsewhere in the component.
<div
ref={
(loadingMessage) => {
this.loadingMessage = loadingMessage;
}
}
tabIndex='-1'
>
Loading…
</div>
ref…
componentDidMount() {
this.loadingMessage.focus();
}
When using React Router's <Link /> component, the browser never actually reloads, leaving the user's focus state in an unknown position.
ref
<div
ref={
(contentContainer) => {
this.contentContainer = contentContainer;
}
}
tabIndex="-1"
aria-labelledby="pageHeading"
>
<Header />
<h1 id="pageHeading">…</h1>
// Content components…
<Footer />
</div>
ref
componentDidMount() {
this.contentContainer.focus();
}
ref syntaxReact 16.3 will be introducing a new, simpler way to create refs.
Now, if after learning about how to create a ref using the function syntax is a little confusing (and it is for me, too) there's actually a brand new way to create a ref which is coming in React 16.3.
Let's take a look at an example of this new syntax…
👇createRef() method
// 1. Create a new class property
loading = React.createRef();
// 2. Assign the class property to
// the element via ref prop
<div ref={this.loading} tabIndex="-1">
Loading…
</div>
// 3. Call the focus method within componentDidMount
this.loading.value.focus();
Coming back to the Loading component example, the snippets of code on the screen here gives a general outline of the new ref syntax.
loading equals React.createRef. This creates a new class property called loading and creates a new ref object for use later in the component.ref object created, the next step is to assign the ref to an element using the ref prop. On the screen is a div element with its ref prop being assigned, this.loading. At this point, the loading class property we created in the first step now references the div in our render method.loading class property. With this example of sending focus to the div when the component loads, we can add a single line of code within the Loading component's componentDidMount method. The line reads, this.loading.value.focus. And with this, focus would be send to the div when the component loads onto the screen.
So, you may have noticed the value node of that last line. This represents the actual element which has been assigned to the ref object. In this example, it represents the div element.
With this in mind you might imagine what we'd need to write in order to get the current value of an input element. It would look something like this.refName.value.value. So that may look a little odd when it's written out, but that's how its done.
Fragment components 🍰
Let's talk about a new feature available now as of React 16.2, Fragment components.
What are fragments and why should we use them? How do they help with accessibility of our apps?
Let's answer these questions…
👇Fragments?Fragments let you group a list of elements/child components without adding extra nodes to the DOM.
So, what are Fragments?
Fragments let you group a list of elements or child components together without adding extra nodes to the DOM.
Since React component templates must be wrapped with an element in order to be returned within the render method, often times developers will just wrap with a div. This works, but if you're not careful, this might also lead to invalid HTML.
With Fragments, we can now wrap templates with a "fragment element." When the component is rendered, the Fragment element itself is not sent to the DOM, rendering only the HTML required to properly output your content.
👇div…
render() {
return (
<div>
<td>Hello</td>
<td>World</td>
</div>
);
}
For example…
render method with a return statement.div element which is wrapping some table cell, td elements with the word "hello" in one and "world" in the other.I think it's safe to say this compoent is meant to be a child of some other data table component.
Wrapping template code with a div like this is very common. But if you were to wrap table content with a div element here…
<table>
<tr>
<div>
<td>Hello</td>
<td>World</td>
</div>
</tr>
</table>
…it would result in invalid HTML being generated and sent to the browser: divs are not valid child elements of table rows.
So, how do we meet React's requirement of wrapping content with a single element without generating invalid HTML?
[Any guesses from the audience]
👇React.Fragment
render() {
return (
<React.Fragment>
<td>Hello</td>
<td>World</td>
</React.Fragment>
);
}
You guessed it, with a Fragment!
Now the code snippet on the screen features a Fragment element which is wrapping the td element table cells.
With this we can check out how the generated markup is looking…
👇
<table>
<tr>
<td>Hello</td>
<td>World</td>
</tr>
</table>
And here's the result…
That looks much better! Semantic, valid HTML with no extra wrapper elements. Nice!
👇
React has an accessibility linter which is pre-packaged with each app.
As a general note, a code linter is a handy tool which helps to ensure clean code, or code standards as determined by the team or individual. In other words, they let you know when something's not quite right.
Let's look at a few ways we can use the linter to help ensure a more accessible React app.
👇eslint-plugin-jsx-a11yOutputs errors to the browser console automatically.
<img src="images/chrome-console.png" />
The linter in question is called "eslint-plugin-jsx-a11y" and it comes with each app created with the "create-react-app" utility.
By default, without any setup or configuration on your part, the linter outputs errors found to the browser devtools console.
For example…
img element with a valid src attribute, but it's missing its alt attribute. [Does anyone know what happens when a screen reader interacts with an image with no alt attribute?]img elements must have an alt prop, either with meaningful text, or an empty string for decorative images"Let's output errors directly in the editor, too.
Outputting errors to the console like that is pretty helpful, but I think this would be even better if these errors were displayed in my editor while I'm writing code.
On the screen here is a screenshot of my Atom editor outputting an accessibility error with my code. It's the same error as in the console in the previous slide.
So, let's see how we can set this up.
👇First install the ESLint plugin for your editor. This is usually done within the editor as part of the editor package manager.
I've got links to some of the more popular editors these days. The names of the plugins include:
eslint-plugin-jsx-a11y
npm install eslint eslint-plugin-jsx-a11y --save-dev
Next, install ESLint and the eslint-plugin-jsx-a11y packages from npm.
You would asccomplish this by opening your terminal application, changing to your app directory, and typing:
npm install eslint eslint dash plugin dash jsx dash a11y dash dash save dash dev
This command will install these utilities only for your current project, as each project you work on could have a different configuration.
👇.eslintrc fileAdd to the "plugins" section:
"plugins": [
"jsx-a11y"
]
Add to the "extends" section:
"extends": [
"plugin:jsx-a11y/recommended"
]
The last thing to do is update, or create if it doesn't exist, your project's eslint.rc file.
In the plugins section of this file, you'd add "jsx dash a11y." This loads the accessibility plugin for use with your editor's ESLint plugin.
In the extends section, you'd add "plugin colon jsx dash a11y forward-slash recommended." This loads the default, recommended rules for the plugin to test your code against.
So, after this is all done, you'd just restart your editor and you should see some errors come up when you've got some accessibility issues in your code!
👉
The last thing I want to discuss is writing HTML in React.
In the past I've been asked the very broad, open ended question, "How accessible is React?"
This was coming from the knowledge that other frameworks or libraries had great difficulty when it came to accessibility as a result of the framework team providing third-party user interfaces and components.
In other words, if something wasn't accessible, there's not a great chance of it actually getting fixed as it relied on a third-party team.
👇
On this slide is a relavent quote from Heydon Pickering. It reads…
React code doesn't have to be inaccessible any more than hip-hop has to be misogynist.
I believe this to be true and is actually a nice seguey into my next point…
👇Since React uses ES6 classes and standard HTML markup to generate its components, it’s up to you to continue to write good, clean, semantic HTML.
What I've found is that since React uses ES6 classes and standard HTML markup within its templates to create and export components, it's up to you, the developer, to continue to write valid, semantic HTML.
With the exception of using a third-party module from npm it's really all up to you. React doesn't force you to use something that someone else made, thus lowering the risk of creating an inaccessible product.
If there are accessibility issues, it's your fault . This is a good thing! 👍
In other words; if there are any accessibility issues, it's your fault.
And this is a good thing!
It's up to you as the developer to fix these issues. You don't have to wait for a third-party developer group to maybe get around to fixing these issues someday. You can do it youself, today.
👇
Check out the demo app, TV-Db 👉.
title updatetitle being updatedWhat we witnessed in the demo…
title being updated
Just announced TODAY by Ryan Florence: Reach Router: An Accessible Router for React.
Thank you, everyone!
[Questions?]