mirror of
https://github.com/reactjs/react.dev.git
synced 2026-02-22 11:52:00 +00:00
[accessibility] Minor clarifications (#1100)
* [accessibility] Remove trailing whitespaces * [accessibility] Minor clarifications * [accessibility] Minor clarifications (review changes) * Language
This commit is contained in:
@@ -26,11 +26,11 @@ The following WCAG checklists provide an overview:
|
||||
|
||||
The [Web Accessibility Initiative - Accessible Rich Internet Applications](https://www.w3.org/WAI/intro/aria) document contains techniques for building fully accessible JavaScript widgets.
|
||||
|
||||
Note that all `aria-*` HTML attributes are fully supported in JSX. Whereas most DOM properties and attributes in React are camelCased, these attributes should be lowercased:
|
||||
Note that all `aria-*` HTML attributes are fully supported in JSX. Whereas most DOM properties and attributes in React are camelCased, these attributes should be hyphen-cased (also known as kebab-case, lisp-case, etc) as they are in plain HTML:
|
||||
|
||||
```javascript{3,4}
|
||||
<input
|
||||
type="text"
|
||||
type="text"
|
||||
aria-label={labelText}
|
||||
aria-required="true"
|
||||
onChange={onchangeHandler}
|
||||
@@ -46,18 +46,27 @@ in our websites will often give us accessibility for free.
|
||||
- [MDN HTML elements reference](https://developer.mozilla.org/en-US/docs/Web/HTML/Element)
|
||||
|
||||
Sometimes we break HTML semantics when we add `<div>` elements to our JSX to make our React code work, especially when working with lists (`<ol>`, `<ul>` and `<dl>`) and the HTML `<table>`.
|
||||
In these cases we should rather use React Fragments to group together multiple elements.
|
||||
In these cases we should rather use [React Fragments](/docs/fragments.html) to group together multiple elements.
|
||||
|
||||
Use `<Fragment>` when a `key` prop is required:
|
||||
|
||||
```javascript{1,8,11}
|
||||
For example,
|
||||
|
||||
```javascript{1,5,8,18,21}
|
||||
import React, { Fragment } from 'react';
|
||||
|
||||
function ListItem({ item }) {
|
||||
return (
|
||||
<Fragment>
|
||||
<dt>{item.term}</dt>
|
||||
<dd>{item.description}</dd>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
function Glossary(props) {
|
||||
return (
|
||||
<dl>
|
||||
{props.items.map(item => (
|
||||
// Without the `key`, React will fire a key warning
|
||||
// Fragments should also have a `key` prop when mapping collections
|
||||
<Fragment key={item.id}>
|
||||
<dt>{item.term}</dt>
|
||||
<dd>{item.description}</dd>
|
||||
@@ -68,18 +77,20 @@ function Glossary(props) {
|
||||
}
|
||||
```
|
||||
|
||||
Use `<></>` syntax everywhere else:
|
||||
When you don't need any props on the Fragment tag you can also use the [short syntax](/docs/fragments.html#short-syntax), if your tooling supports it:
|
||||
|
||||
```javascript
|
||||
```javascript{3,6}
|
||||
function ListItem({ item }) {
|
||||
return (
|
||||
return (
|
||||
<>
|
||||
<dt>{item.term}</dt>
|
||||
<dd>{item.description}</dd>
|
||||
</>
|
||||
);
|
||||
);
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
For more info, see [the Fragments documentation](/docs/fragments.html).
|
||||
|
||||
## Accessible Forms
|
||||
|
||||
@@ -108,7 +119,7 @@ Error situations need to be understood by all users. The following link shows us
|
||||
|
||||
## Focus Control
|
||||
|
||||
Ensure that your web application can be fully operated with the keyboard only:
|
||||
Ensure that your web application can be fully operated with the keyboard only:
|
||||
|
||||
- [WebAIM talks about keyboard accessibility](http://webaim.org/techniques/keyboard/)
|
||||
|
||||
@@ -124,7 +135,7 @@ Only ever use CSS that removes this outline, for example by setting `outline: 0`
|
||||
|
||||
Provide a mechanism to allow users to skip past navigation sections in your application as this assists and speeds up keyboard navigation.
|
||||
|
||||
Skiplinks or Skip Navigation Links are hidden navigation links that only become visible when keyboard users interact with the page. They are very easy to implement with
|
||||
Skiplinks or Skip Navigation Links are hidden navigation links that only become visible when keyboard users interact with the page. They are very easy to implement with
|
||||
internal page anchors and some styling:
|
||||
|
||||
- [WebAIM - Skip Navigation Links](http://webaim.org/techniques/skipnav/)
|
||||
@@ -137,7 +148,7 @@ Read more about the use of these elements to enhance accessibility here:
|
||||
|
||||
### Programmatically managing focus
|
||||
|
||||
Our React applications continuously modify the HTML DOM during runtime, sometimes leading to keyboard focus being lost or set to an unexpected element. In order to repair this,
|
||||
Our React applications continuously modify the HTML DOM during runtime, sometimes leading to keyboard focus being lost or set to an unexpected element. In order to repair this,
|
||||
we need to programmatically nudge the keyboard focus in the right direction. For example, by resetting keyboard focus to a button that opened a modal window after that modal window is closed.
|
||||
|
||||
MDN Web Docs takes a look at this and describes how we can build [keyboard-navigable JavaScript widgets](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Keyboard-navigable_JavaScript_widgets).
|
||||
@@ -208,7 +219,7 @@ When using a HOC to extend components, it is recommended to [forward the ref](/d
|
||||
does not implement ref forwarding, the above pattern can still be used as a fallback.
|
||||
|
||||
A great focus management example is the [react-aria-modal](https://github.com/davidtheclark/react-aria-modal). This is a relatively rare example of a fully accessible modal window. Not only does it set initial focus on
|
||||
the cancel button (preventing the keyboard user from accidentally activating the success action) and trap keyboard focus inside the modal, it also resets focus back to the element that
|
||||
the cancel button (preventing the keyboard user from accidentally activating the success action) and trap keyboard focus inside the modal, it also resets focus back to the element that
|
||||
initially triggered the modal.
|
||||
|
||||
>Note:
|
||||
@@ -221,7 +232,7 @@ initially triggered the modal.
|
||||
Ensure that all functionality exposed through a mouse or pointer event can also be accessed using the keyboard alone. Depending only on the pointer device will lead to many cases where
|
||||
keyboard users cannot use your application.
|
||||
|
||||
To illustrate this, let's look at a prolific example of broken accessibility caused by click events. This is the outside click pattern, where a user can disable an opened popover by clicking outside the element.
|
||||
To illustrate this, let's look at a prolific example of broken accessibility caused by click events. This is the outside click pattern, where a user can disable an opened popover by clicking outside the element.
|
||||
|
||||
<img src="../images/docs/outerclick-with-mouse.gif" alt="A toggle button opening a popover list implemented with the click outside pattern and operated with a mouse showing that the close action works." />
|
||||
|
||||
@@ -258,7 +269,7 @@ constructor(props) {
|
||||
this.setState({ isOpen: false });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div ref={this.toggleContainer}>
|
||||
@@ -276,7 +287,7 @@ constructor(props) {
|
||||
}
|
||||
```
|
||||
|
||||
This may work fine for users with pointer devices, such as a mouse, but operating this with the keyboard alone leads to broken functionality when tabbing to the next element
|
||||
This may work fine for users with pointer devices, such as a mouse, but operating this with the keyboard alone leads to broken functionality when tabbing to the next element
|
||||
as the `window` object never receives a `click` event. This can lead to obscured functionality which blocks users from using your application.
|
||||
|
||||
<img src="../images/docs/outerclick-with-keyboard.gif" alt="A toggle button opening a popover list implemented with the click outside pattern and operated with the keybard showing the popover not being closed on blur and it obscuring other screen elements." />
|
||||
@@ -301,11 +312,11 @@ class BlurExample extends React.Component {
|
||||
isOpen: !currentState.isOpen
|
||||
}));
|
||||
}
|
||||
|
||||
// We close the popover on the next tick by using setTimeout.
|
||||
// This is necessary because we need to first check if
|
||||
|
||||
// We close the popover on the next tick by using setTimeout.
|
||||
// This is necessary because we need to first check if
|
||||
// another child of the element has received focus as
|
||||
// the blur event fires prior to the new focus event.
|
||||
// the blur event fires prior to the new focus event.
|
||||
onBlurHandler() {
|
||||
this.timeOutId = setTimeout(() => {
|
||||
this.setState({
|
||||
@@ -320,13 +331,13 @@ class BlurExample extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
// React assists us by bubbling the blur and
|
||||
// React assists us by bubbling the blur and
|
||||
// focus events to the parent.
|
||||
return (
|
||||
<div onBlur={this.onBlurHandler}
|
||||
<div onBlur={this.onBlurHandler}
|
||||
onFocus={this.onFocusHandler}>
|
||||
<button onClick={this.onClickHandler}
|
||||
aria-haspopup="true"
|
||||
<button onClick={this.onClickHandler}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={this.state.isOpen}>
|
||||
Select an option
|
||||
</button>
|
||||
@@ -343,8 +354,8 @@ class BlurExample extends React.Component {
|
||||
}
|
||||
```
|
||||
|
||||
This code exposes the functionality to both pointer device and keyboard users. Also note the added `aria-*` props to support screen-reader users. For simplicity's sake
|
||||
the keyboard events to enable `arrow key` interaction of the popover options have not been implemented.
|
||||
This code exposes the functionality to both pointer device and keyboard users. Also note the added `aria-*` props to support screen-reader users. For simplicity's sake
|
||||
the keyboard events to enable `arrow key` interaction of the popover options have not been implemented.
|
||||
|
||||
<img src="../images/docs/blur-popover-close.gif" alt="A popover list correctly closing for both mouse and keyboard users." />
|
||||
|
||||
@@ -409,11 +420,11 @@ By far the easiest and also one of the most important checks is to test if your
|
||||
1. Plugging out your mouse.
|
||||
1. Using `Tab` and `Shift+Tab` to browse.
|
||||
1. Using `Enter` to activate elements.
|
||||
1. Where required, using your keyboard arrow keys to interact with some elements, such as menus and dropdowns.
|
||||
1. Where required, using your keyboard arrow keys to interact with some elements, such as menus and dropdowns.
|
||||
|
||||
### Development assistance
|
||||
|
||||
We can check some accessibility features directly in our JSX code. Often intellisense checks are already provided in JSX aware IDE's for the ARIA roles, states and properties. We also
|
||||
We can check some accessibility features directly in our JSX code. Often intellisense checks are already provided in JSX aware IDE's for the ARIA roles, states and properties. We also
|
||||
have access to the following tool:
|
||||
|
||||
#### eslint-plugin-jsx-a11y
|
||||
@@ -421,9 +432,9 @@ have access to the following tool:
|
||||
The [eslint-plugin-jsx-a11y](https://github.com/evcohen/eslint-plugin-jsx-a11y) plugin for ESLint provides AST linting feedback regarding accessibility issues in your JSX. Many
|
||||
IDE's allow you to integrate these findings directly into code analysis and source code windows.
|
||||
|
||||
[Create React App](https://github.com/facebookincubator/create-react-app) has this plugin with a subset of rules activated. If you want to enable even more accessibility rules,
|
||||
[Create React App](https://github.com/facebookincubator/create-react-app) has this plugin with a subset of rules activated. If you want to enable even more accessibility rules,
|
||||
you can create an `.eslintrc` file in the root of your project with this content:
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"extends": ["react-app", "plugin:jsx-a11y/recommended"],
|
||||
@@ -450,7 +461,7 @@ The [Web Accessibility Evaluation Tool](http://wave.webaim.org/extension/) is an
|
||||
|
||||
#### Accessibility inspectors and the Accessibility Tree
|
||||
|
||||
[The Accessibility Tree](https://www.paciellogroup.com/blog/2015/01/the-browser-accessibility-tree/) is a subset of the DOM tree that contains accessible objects for every DOM element that should be exposed
|
||||
[The Accessibility Tree](https://www.paciellogroup.com/blog/2015/01/the-browser-accessibility-tree/) is a subset of the DOM tree that contains accessible objects for every DOM element that should be exposed
|
||||
to assistive technology, such as screen readers.
|
||||
|
||||
In some browsers we can easily view the accessibility information for each element in the accessibility tree:
|
||||
@@ -477,7 +488,7 @@ Refer to the following guides on how to best use NVDA:
|
||||
|
||||
#### VoiceOver in Safari
|
||||
|
||||
VoiceOver is an integrated screen reader on Apple devices.
|
||||
VoiceOver is an integrated screen reader on Apple devices.
|
||||
|
||||
Refer to the following guides on how activate and use VoiceOver:
|
||||
|
||||
@@ -487,7 +498,7 @@ Refer to the following guides on how activate and use VoiceOver:
|
||||
|
||||
#### JAWS in Internet Explorer
|
||||
|
||||
[Job Access With Speech](http://www.freedomscientific.com/Products/Blindness/JAWS) or JAWS, is a prolifically used screen reader on Windows.
|
||||
[Job Access With Speech](http://www.freedomscientific.com/Products/Blindness/JAWS) or JAWS, is a prolifically used screen reader on Windows.
|
||||
|
||||
Refer to the following guides on how to best use JAWS:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user