Créer des applications React accessibles
La bibliothèque React JavaScript est un excellent moyen de créer des composants modulaires réutilisables pouvant être partagés entre plusieurs projets. Mais comment vous assurez-vous que vos applications React sont utilisables par toutes sortes de personnes ?
En février 2017, j'ai pris un train de Kingston, au Canada, au centre-ville de Toronto. Pourquoi faisais-je ce trajet de deux heures ? Pour en savoir plus sur la bibliothèque React JavaScript.
À la fin du cours d'une journée, nous avons chacun développé une application entièrement fonctionnelle. L'une des choses qui m'a vraiment enthousiasmé à propos de React était la façon dont cela vous oblige à penser de manière modulaire. Chaque composant effectue une tâche, et il le fait très bien. Lorsque vous construisez des composants de cette façon, cela vous aide à concentrer toute votre réflexion et votre énergie pour vous assurer que vous effectuez la bonne tâche, non seulement pour votre projet actuel, mais aussi pour les projets futurs. Les composants React sont réutilisables et, s'ils sont bien construits, peuvent être partagés entre les projets. Il suffit de trouver la bonne brique Lego dans la pile pour assembler ce dont vous avez besoin afin de créer une expérience utilisateur exceptionnelle.
Cependant, à mon retour de voyage, j'ai commencé à me demander si l'application que j'avais créée ce jour-là était accessible. Pourrait-il être rendu accessible ? Après avoir chargé le projet sur mon ordinateur portable, j'ai entrepris d'effectuer des tests de base avec mon clavier et mon lecteur d'écran VoiceOver.
Il y avait quelques problèmes mineurs de type gain rapide, tels que l'utilisation d'éléments ul
+ li
pour la liste de liens de la page d'accueil au lieu de l'offre actuelle d'éléments div
. Autre gain rapide : ajouter un attribut alt
vide pour les conteneurs de légende avec des images décoratives.
Il y avait aussi des problèmes plus difficiles à surmonter. À chaque nouveau chargement de page, le texte de l'élément de title
ne changeait pas pour refléter le nouveau contenu. Non seulement cela, mais le focus du clavier était très mal géré, ce qui empêcherait les utilisateurs utilisant uniquement le clavier d'utiliser l'application. Lorsqu'une nouvelle page était chargée, le focus restait sur la vue de page précédente !
Y avait-il des techniques à utiliser pour résoudre ces problèmes d'accessibilité plus difficiles ?
Après avoir passé du temps à lire les docs React et à essayer certaines des techniques acquises pendant le cours, j'ai pu rendre l'application beaucoup plus accessible. Dans cet article, je vais vous expliquer les problèmes d'accessibilité les plus urgents et la manière de les résoudre, notamment :
- Réagissez mots réservés;
- mettre à jour le titre de la page ;
- gérer le focus du clavier ;
- créer un composant de messagerie en direct ;
- le linting de code, ainsi que quelques réflexions supplémentaires sur la création d'applications React accessibles.
Application de démonstration
Si voir le code en action est plus votre style, consultez l'application de démonstration React qui accompagne cet article : TV-Db .
Vous pouvez également suivre la lecture de cet article en suivant les liens en ligne vers le code source de l'application de démonstration .
Prêt à vous assurer que vos applications React sont plus inclusives pour les personnes handicapées et tous les types d'utilisateurs ? Allons-y!
Attributs HTML et mots réservés
Une chose à garder à l'esprit lors de l'écriture de HTML dans les composants React est que les attributs HTML doivent être écrits en camelCase
. Cela m'a pris par surprise au début, mais je me suis vite habitué. Si vous finissez par insérer un attribut tout en lowercase
par accident, vous recevrez un avertissement convivial dans la console JavaScript pour vous adapter à camelCase
.
Par exemple, l'attribut tabindex
doit être écrit sous tabIndex
(notez le caractère 'I' en majuscule). L'exception à cette règle est que tous les attributs data- data-*
ou aria-*
sont toujours écrits comme prévu.
Il existe également quelques mots réservés en JavaScript qui correspondent à des noms d'attributs HTML spécifiques. Ceux-ci ne peuvent pas être écrits de la même manière que vous attendez:
-
for
est un mot réservé en JavaScript qui est utilisé pour parcourir les éléments. Lors de la création d'éléments d'label
dans les composants React, vous devez utiliser l'attributhtmlFor
à la place pour définir la relation explicitelabel
+input
. -
class
est également un mot réservé en JavaScript. Lors de l'attribution d'un attribut declass
sur un élément HTML pour le style, il doit être écrit en tant queclassName
à la place.
Il y a probablement plus d'attributs à surveiller, mais jusqu'à présent, ce sont les seuls conflits que j'ai trouvés en ce qui concerne les mots réservés JavaScript et les attributs HTML. Avez-vous rencontré d'autres conflits ? Postez cela dans les commentaires, et nous publierons un post de suivi avec toute la liste !
Définir le titre de la page
Étant donné que les applications React sont des SPA (applications à page unique), l'élément de title
affichera le même contenu défini tout au long de la session de navigation ; ce n'est pas idéal.
L'élément de
title
de la page est généralement le premier élément de contenu annoncé par les lecteurs d'écran lors du chargement de la page.
Il est essentiel que le titre reflète le contenu de la page, afin que les personnes qui en dépendent et rencontrent ce contenu en premier sauront à quoi s'attendre.
Dans les applications React, le contenu de l'élément de title
est défini dans le fichier public/index.html
, puis n'est plus jamais touché.
Nous pouvons contourner ce problème en définissant dynamiquement le contenu de l'élément de title
dans nos composants parents, ou "pages" selon les besoins, en attribuant une valeur à la propriété globale document.title
. Nous définissons ceci dans la méthode de cycle de vie componentWillMount()
de React. Il s'agit d'une fonction que vous utilisez pour exécuter des extraits de code lors du chargement de la page.
Par exemple, si la page est une page "Contactez-nous" avec des informations de contact ou un formulaire de contact, nous pourrions appeler la méthode de cycle de vie componentWillMount()
comme {[Home.js:23](https://github.com/svinkle/tv-db/blob/master/src/pages/Home.js#L23)}
:
componentWillMount() { document.title = 'Contact us | Site Name'; }
Lorsque cette "page" de composant se charge, observez la mise à jour de la valeur dans l'onglet du navigateur vers "Contactez-nous | Nom du site". Assurez-vous simplement d'ajouter le même code ci-dessus afin de mettre à jour l'élément de title
pour tous les composants de votre page.
Gestion de la concentration, première partie
Parlons de la gestion de la concentration, un facteur important pour garantir que votre application est à la fois accessible et une expérience utilisateur réussie. Si vos clients essaient de remplir un formulaire de plusieurs "pages" et que vous ne gérez pas le focus avec chaque vue, cela risque de semer la confusion, et s'ils utilisent des technologies d'assistance, il peut être trop difficile pour eux de continuer pour remplir le formulaire. Vous pourriez les perdre entièrement en tant que clients.
Afin de définir le focus du clavier sur un élément spécifique d'un composant, vous devez créer ce qu'on appelle une "ref de fonction" ou ref
en abrégé. Si vous commencez tout juste à apprendre React, vous pouvez penser à une ref
de la même manière que la sélection d'un élément HTML dans le DOM avec jQuery et sa mise en cache dans une variable, telle que :
var myBtn = $('#myBtn');
Une chose unique lors de la création de la ref
est qu'elle peut être nommée n'importe quoi (si tout va bien quelque chose qui a du sens pour vous et les autres développeurs de l'équipe) et ne repose pas sur un id
ou une class
pour un sélecteur.
Par exemple, si vous avez un écran de chargement, il serait idéal d'envoyer le focus au conteneur de message "chargement" afin qu'un lecteur d'écran annonce l'état actuel de l'application. Dans votre composant de chargement, vous pouvez créer une ref
pour pointer vers le conteneur de chargement {[Loader.js:29](https://github.com/svinkle/tv-db/blob/master/src/components/Loader.js#L29)}
:
<div tabIndex="-1" ref={ (loadingContainer) => { this.loadingContainer = loadingContainer; } } > <p>Loading…</p> </div>
Lorsque ce composant est rendu, la function ref
se déclenche et crée une "référence" à l'élément en créant une nouvelle propriété de classe. Dans ce cas, nous créons une référence à la div
appelée "loadingContainer" et nous la passons à une nouvelle propriété de classe via this.loadingContainer = loadingContainer
instruction d'affectation.
Nous utilisons la ref
dans le hook de cycle de vie componentDidMount()
pour définir explicitement le focus sur le conteneur "loading" lorsque le composant charge {[Loader.js:12](https://github.com/svinkle/tv-db/blob/master/src/components/Loader.js#L12)}
:
componentDidMount() { this.loadingContainer.focus(); }
Au moment où le composant de chargement est supprimé de la vue, vous pouvez utiliser une ref
différente pour déplacer le focus ailleurs.
On ne peut vraiment pas exagérer à quel point il est important de gérer le focus sur un élément et de gérer le focus d' un élément à un autre. C'est l'un des plus grands défis lors de la création d'applications à page unique pour obtenir une bonne accessibilité.
Messagerie en direct
La messagerie en direct est un excellent moyen d'annoncer les changements d'état de votre application. Par exemple, lorsque des données ont été ajoutées à la page, il est utile d'informer les personnes disposant de certains types de technologies d'assistance, comme les lecteurs d'écran, que cet événement a eu lieu, ainsi que le nombre d'éléments désormais disponibles.
Passons en revue et créons un moyen de gérer les annonces en direct en créant un nouveau composant. Nous allons appeler ce nouveau composant : Announcements
.
Lorsque le composant est rendu, la valeur this.props.message
sera injectée dans l'élément aria-live
, ce qui lui permettra d'être annoncé par les lecteurs d'écran.
Le composant ressemble à quelque chose comme {[Announcements.js:12](https://github.com/svinkle/tv-db/blob/master/src/components/Announcements.js#L12)}
:
import React from 'react'; class Announcements extends React.Component { render() { return ( <div className="visuallyhidden" aria-live="polite" aria-atomic="true"> {this.props.message} </div> ); } } export default Announcements;
Ce composant crée simplement un élément div
avec quelques attributs liés à l'accessibilité : aria-live
et aria-atomic
. Les lecteurs d'écran liront ces attributs et annonceront tout texte dans la div
à haute voix pour que la personne utilisant votre application puisse l'entendre. L'attribut aria-live
est assez puissant, alors utilisez-le judicieusement.
De plus, il est important de toujours restituer le composant Announcement
dans le modèle, car certaines technologies de navigateur/lecteur d'écran n'annoncent pas le contenu lorsque l'élément aria-live
est ajouté dynamiquement au DOM. Par conséquent, ce composant doit toujours être inclus dans tous les composants parents de votre application.
Vous incluriez le composant Announcement
comme {[Results.js:91](https://github.com/svinkle/tv-db/blob/master/src/pages/Results.js#L91)}
:
<Announcements message="{this.state.announcementMessage}" />
Afin de transmettre le message au composant Annonces, créez une propriété d'état dans le composant parent qui sera utilisée pour contenir le texte du message {[Results.js:22](https://github.com/svinkle/tv-db/blob/master/src/pages/Results.js#L22)}
:
this.state = { announcementMessage: null };
Ensuite, mettez à jour l'état si nécessaire {[Results.js:62](https://github.com/svinkle/tv-db/blob/master/src/pages/Results.js#L62)}
:
this.setState({ announcementMessage: `Total results found: ${data.length}` });
Gestion des focus, deuxième partie
Nous avons déjà appris à gérer le focus à l'aide de ref
s, le concept React de création d'une variable pointant vers un élément du DOM. Maintenant, regardons un autre exemple très important utilisant le même concept.
Lorsque vous créez un lien vers d'autres pages de votre application, vous pouvez utiliser l'élément HTML a
. Ce faisant, cela entraînera un rechargement complet de la page comme on pouvait s'y attendre. Cependant, si vous utilisez React Router dans votre application, vous avez accès au composant Link
. Le composant Link
remplace en fait l' a
éprouvé dans les applications React.
Pourquoi utiliseriez-vous Link
au lieu de véritables liens d'ancrage HTML, demandez-vous ? Bien qu'il soit parfaitement acceptable d'utiliser des liens HTML dans les composants React, l'utilisation du composant Link
de React Router permet à votre application de tirer parti du DOM virtuel de React. L'utilisation du composant Link
aide à charger les "pages" beaucoup plus rapidement car le navigateur n'a pas besoin de se rafraîchir lors d'un clic sur Link
, mais elles ont un hic.
Lorsque vous utilisez des composants
Link
, vous devez savoir où se trouve le focus du clavier et où il ira lorsque la "page" suivante apparaîtra.
C'est là que notre ami ref
vient nous aider.
Composants de lien
Un composant Link typique ressemble à ceci :
<Link to='/home'>Home</Link>
La syntaxe devrait vous sembler familière car elle est assez similaire à a
élément HTML a ; échangez le a
pour Link
et href
avec to
et vous êtes prêt.
Comme je l'ai déjà mentionné, l'utilisation de composants Link
au lieu de liens HTML ne rafraîchit pas le navigateur. Au lieu de cela, React Router charge le composant suivant comme décrit dans to
prop.
Voyons comment nous pouvons nous assurer que le focus du clavier se déplace vers un endroit approprié.
Réglage du focus du clavier
Lorsqu'une nouvelle page se charge, le focus du clavier doit être explicitement défini. Sinon, le focus reste sur la page précédente, et qui sait où le focus pourrait se retrouver lorsque quelqu'un commencera à naviguer ensuite ? Comment définissons-nous explicitement le focus ? Notre cher ami ref
.
Mise en place de la réf
Pour décider où le focus doit aller, vous devrez examiner comment vos composants ont été configurés et quels widgets sont utilisés. Par exemple, si vous avez des composants "page" avec des composants enfants constituant le reste du contenu de la page, vous pouvez déplacer le focus vers l'élément parent le plus à l'extérieur de la page, très probablement un élément div
. À partir de là, quelqu'un pourrait naviguer dans le reste du contenu de la page, un peu comme s'il y avait une actualisation complète du navigateur.
Créons une ref
appelée contentContainer
sur la div
parent la plus externe, comme {[Details.js:84](https://github.com/svinkle/tv-db/blob/master/src/pages/Details.js#L84)}
:
<div ref={ (contentContainer) => { this.contentContainer = contentContainer; } } tabIndex="-1" aria-labelledby="pageHeading" \>
Vous avez peut-être remarqué l'inclusion des tabIndex
et aria-labelledby
. Le tabIndex
avec sa valeur définie sur -1
permettra à l'élément div
normalement non focalisable de recevoir le focus du clavier, par programmation via ref
.
Astuce : Tout comme la gestion des focus, utilisez
tabIndex="-1"
intentionnellement et selon un plan explicite.
La valeur de l'attribut aria-labelledby
associera par programme l'en-tête de la page (peut-être un élément h1
ou h2
avec l'id de "pageHeading") pour aider à décrire le contexte actuel de l'endroit où le clavier est actuellement focalisé.
Maintenant que nous avons créé la ref
, voyons comment nous l'utilisons pour déplacer le focus.
Utilisation de la réf
Nous avons appris plus tôt la méthode de cycle de vie componentDidMount()
. Nous pouvons l'utiliser à nouveau pour déplacer le focus du clavier lorsque la page se charge dans le DOM virtuel de React, en utilisant la ref
contentContainer
que nous avons créée précédemment dans le composant {[Home.js:26](https://github.com/svinkle/tv-db/blob/master/src/pages/Home.js#L26)}
:
componentDidMount() { this.contentContainer.focus(); }
Le code ci-dessus indique à React "lors du chargement du composant, déplacez le focus du clavier vers l'élément conteneur". À partir de ce moment, la navigation commencera en haut de la page et le contenu sera détectable comme si une actualisation complète de la page avait eu lieu.
Linter du code d'accessibilité de React
Je ne pouvais pas écrire un article React sur l'accessibilité sans mentionner l'incroyable projet open-source qu'est [eslint-plugin-jsx-a11y](https://github.com/evcohen/eslint-plugin-jsx-a11y)
. Il s'agit d'un plugin ESLint , spécifiquement pour JSX et React, qui surveille et signale tout problème d'accessibilité potentiel avec votre code. Il est intégré lorsque vous créez un nouveau projet React, vous n'avez donc pas à vous soucier de la configuration.
Par exemple, si vous avez inclus une image dans votre composant sans attribut alt
, vous verrez ceci dans la console des outils de développement de votre navigateur :
Des messages comme ceux-ci sont vraiment utiles lors du développement d'une application. Cependant, ne serait-il pas formidable de voir ces types de messages dans votre propre éditeur de code, avant même que quoi que ce soit n'arrive au navigateur ? Voici comment installer et configurer eslint-plugin-jsx-a11y
pour une utilisation avec votre environnement d'édition.
Installez le plug-in ESLint
Vous aurez d'abord besoin du plugin ESLint installé pour votre éditeur. Recherchez "eslint" dans les référentiels de plugins de votre éditeur - il y a de fortes chances qu'il y ait quelque chose que vous puissiez installer.
Voici quelques liens rapides pour :
Installer eslint-plugin-jsx-a11y
L'étape suivante consiste à installer eslint-plugin-jsx-a11y
via npm
. Exécutez simplement la commande suivante pour l'installer et ESLint pour une utilisation dans votre éditeur :
npm install eslint eslint- plugin -jsx-a11y --save-dev
Une fois l'exécution terminée, mettez à jour le fichier .eslintrc
du projet afin qu'ESLint puisse utiliser le eslint-plugin-jsx-a11y
.
Mettre à jour la configuration ESLint
S'il n'y a pas de fichier .eslintrc
dans le répertoire racine de votre projet, vous pouvez simplement créer un nouveau fichier avec ceci comme nom de fichier. Découvrez comment configurer le fichier [.eslintrc](https://eslint.org/docs/user-guide/configuring)
et certaines des règles que vous pouvez ajouter pour configurer ESLint afin de répondre aux exigences de votre projet.
Avec le fichier .eslintrc
en place, ouvrez-le pour le modifier et ajoutez ce qui suit à la section "plugins" {[.eslintrc:43](https://github.com/svinkle/tv-db/blob/master/.eslintrc#L43)}
:
"plugins" : [ "jsx-a11y" ]
Cela indique à notre instance locale d'ESLint d'utiliser le plugin jsx-a11y
lors du lintage de vos fichiers de projet.
Pour qu'ESLint recherche des erreurs spécifiques liées à l'accessibilité dans notre code, nous devons également spécifier l'ensemble de règles à utiliser par ESLint. Vous pouvez configurer vos propres règles, mais je vous recommande d'utiliser l'ensemble par défaut, au moins pour commencer.
Ajoutez ce qui suit à la section "extends" du fichier .eslintrc
{[.eslintrc:47](https://github.com/svinkle/tv-db/blob/master/.eslintrc#L47)}
:
"extends" : [ "plugin:jsx-a11y/recommended" ]
Cette ligne indique à ESLint d'utiliser l'ensemble de règles recommandé par défaut, que je trouve très utile.
Après avoir effectué ces modifications et redémarré votre éditeur, vous devriez maintenant voir quelque chose comme ce qui suit en cas de problèmes liés à l'accessibilité :
Continuer à écrire du HTML sémantique
Dans le document d'aide "Thinking in React" , les lecteurs sont encouragés à créer des modules de composants ou un développement piloté par les composants ; minuscules extraits de code réutilisables. L'avantage est de pouvoir réutiliser le code d'un projet à l'autre. Imaginez, créer un widget accessible pour un site, puis si l'autre site nécessite le même widget, pouvoir copier et coller le code !
À partir de là, vous construisez votre interface utilisateur en utilisant des modules dans des modules pour créer des composants plus volumineux, et finalement une "page" se rassemble. Cela peut poser un peu de courbe d'apprentissage au début, mais après un certain temps, vous vous habituez à cette façon de penser et vous pourriez finir par apprécier le processus de décomposition lors de l'écriture de votre code HTML.
Étant donné que React utilise des classes ES6 pour constituer ses composants, c'est à vous de continuer à écrire du bon HTML sémantique et propre.
Comme nous l'avons évoqué plus tôt dans l'article, il y a quelques mots réservés à surveiller, tels que htmlFor
et className
, mais à part cela, il est toujours de votre responsabilité en tant que développeur d'écrire et de tester votre interface utilisateur HTML comme vous le feriez normalement.
Profitez également de la possibilité d'écrire du JavaScript dans votre code HTML via JSX, le cas échéant. Cela aide grandement à rendre votre application beaucoup plus dynamique et accessible.
Conclusion
Vous êtes maintenant entièrement équipé pour rendre les applications React plus accessibles ! Vous possédez les connaissances pour :
- mettez à jour le
title
de la page afin que les utilisateurs restent orientés dans votre application et comprennent l'objectif du contenu de chaque vue ; - gérer le focus du clavier afin qu'ils puissent se déplacer en douceur dans le contenu dynamique sans se perdre ou se confondre avec ce qui vient de se passer ;
- créer un composant de messagerie en direct pour alerter les gens de tout changement d'état important ; et
- ajoutez du linting de code à votre projet afin de détecter les erreurs d'accessibilité pendant que vous travaillez.
Et peut-être le meilleur conseil d'accessibilité à partager avec quiconque développe pour le Web : écrivez du code HTML sémantique dans vos modèles, comme vous le feriez pour n'importe quel site Web statique, CMS ou basé sur un framework. React ne vous gêne pas lorsqu'il s'agit de choisir les éléments à créer pour vos interfaces utilisateur. C'est à vous, cher développeur, de faire en sorte que ce que vous créez soit utilisable et accessible au plus grand nombre.
Avez-vous découvert d'autres moyens de créer des applications React plus accessibles ? J'aimerais en entendre parler dans les commentaires!