Continue on to find out how…
title
React.Fragment
Write attributes in camelCase 🐪
tabindex
👉 tabIndex
contenteditable
👉 contentEditable
maxlength
👉 maxLength
(aria-*
and data-*
are exempt from this.)
When HTML conflicts with JS 😕
for
👉 htmlFor
class
👉 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 ref
s.
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…
👇Fragment
s?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: div
s 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-a11y
Outputs 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 updatedJust announced TODAY by Ryan Florence: Reach Router: An Accessible Router for React.
Thank you, everyone!
[Questions?]