Erstellen einer barrierefreien Navigationsmenüleiste mit React Hooks

WBOY
Freigeben: 2024-08-08 13:25:29
Original
662 Leute haben es durchsucht

Building an Accessible Navigation Menubar with React Hooks

Publié accidentellement ! Veuillez revenir plus tard pour en savoir plus !

Introduction

Créer des applications Web accessibles n'est pas seulement une bonne pratique, c'est désormais une nécessité. Récemment, j'ai eu l'opportunité de créer une barre de menus de navigation axée sur a11y. Au cours de mes recherches, j'ai réalisé à quel point la plupart des barres de menus ne sont pas conformes au modèle ARIA. Par exemple, au lieu de parcourir les éléments de menu, saviez-vous qu'une barre de menus doit être parcourue avec les touches fléchées et gérer son propre focus ?

Bien que j'ai trouvé quelques tutoriels, je n'ai finalement pas suivi complètement. J'écris ceci parce que je pense que ce que j'ai fini par construire vaut la peine d'être partagé - si vous avez également une affinité avec les petits composants et les crochets personnalisés.

Bien que je structure ce blog avec quelques étapes de développement, mon objectif n'est pas d'écrire un guide étape par étape. Je vous fais confiance pour connaître les bases de React et le fonctionnement des hooks personnalisés.

Je ne partage pour le moment que les principaux détails de mise en œuvre, mais je prévois de mettre à jour cet article avec un exemple de code sandbox à l'avenir lorsque j'aurai plus de temps.

Que construisons-nous ?

Pour ce blog, nous envisageons une barre de menus de navigation, comme celles que vous voyez en haut ou sur le côté de nombreuses applications Web. Dans cette barre de menus, certains éléments de menu peuvent avoir des sous-menus, qui s'ouvriront/se fermeront en entrant/sortant la souris.

Balisage HTML

Tout d'abord, le HTML sémantique et les rôles et attributs ARIA appropriés sont essentiels à l'accessibilité. Pour le modèle de barre de menus, vous pouvez en savoir plus sur la documentation officielle ici.

Voici un exemple de balisage HTML approprié :

Nach dem Login kopieren

Remarquez que nous utilisons la balise bouton pour le HTML sémantique. Le bouton doit également avoir aria-haspopup pour alerter les lecteurs d'écran. Enfin, l'attribut aria-expanded approprié doit être attribué en fonction de l'état du menu.

Composants

Passons en revue les composants dont nous avons besoin. Évidemment, nous avons besoin d'un composant de menu global, ainsi que d'un composant d'élément de menu.

Certains éléments de menu ont un sous-menu, d'autres non. Les éléments de menu avec des sous-menus devront gérer leurs états pour l'ouverture/fermeture du sous-menu lors des événements de survol et de clavier. Il doit donc être son propre composant.

Les sous-menus doivent également être son propre composant. Bien que les sous-menus ne soient également que des conteneurs pour les éléments de menu, ils ne gèrent pas leurs états ni les événements du clavier. Cela les différencie du menu de navigation de niveau supérieur.

J'ai fini par écrire ces composants :

  • NavMenu pour la couche la plus externe des barres de menus.
  • MenuItem pour les éléments de menu individuels.
    • MenuItemLink
    • MenuItemWithSubMenu
  • Sous-menu pour le sous-menu développé. MenuItem peut être imbriqué de manière récursive dans le sous-menu.

Gestion de la concentration

En termes très simples, « gestion de la concentration » signifie simplement que le composant doit savoir quel enfant est concentré. Ainsi, lorsque le focus de l'utilisateur quitte et revient, l'enfant précédemment focalisé sera recentré.

Une technique courante pour la gestion du focus est « Roving Tab Index », où l'élément ciblé dans le groupe a un index de tabulation de 0 et les autres éléments ont un index de tabulation de -1. De cette façon, lorsque l'utilisateur reviendra au groupe de discussion, l'élément avec l'index de tabulation 0 aura automatiquement le focus.

Une première implémentation pour NavMenu peut ressembler à ceci :

export function NavMenu ({ menuItems }) { // state for the currently focused index const [focusedIndex, setFocusedIndex] = useState(0); // functions to update focused index const goToStart = () => setCurrentIndex(0); const goToEnd = () => setCurrentIndex(menuItems.length - 1); const goToPrev = () => { const index = currentIndex === 0 ? menuItems.length - 1 : currentIndex - 1; setCurrentIndex(index); }; const goToNext = () => { const index = currentIndex === menuItems.length - 1 ? 0 : currentIndex + 1; setCurrentIndex(index); }; // key down handler according to aria specification const handleKeyDown = (e) => { e.stopPropagation(); switch (e.code) { case "ArrowLeft": case "ArrowUp": e.preventDefault(); goToPrev(); break; case "ArrowRight": case "ArrowDown": e.preventDefault(); goToNext(); break; case "End": e.preventDefault(); goToEnd(); break; case "Home": e.preventDefault(); goToStart(); break; default: break; } } return (  ); }
Nach dem Login kopieren

Le e.preventDefault() est là pour empêcher des choses comme ArrowDown de faire défiler la page.

Voici le composant MenuItem. Ignorons les éléments du sous-menu juste pendant une seconde. Nous utilisons useEffect, usePrevious et element.focus() pour nous concentrer sur l'élément chaque fois que focusIndex change :

export function MenuItem ({ item, index, focusedIndex, setFocusedIndex }) { const linkRef = useRef(null); const prevFocusedIndex = usePrevious(focusedIndex); const isFocused = index === focusedIndex; useEffect(() => { if (linkRef.current && prevFocusedIndex !== currentIndex && isFocused) { linkRef.current.focus() } }, [isFocused, prevFocusedIndex, focusedIndex]); const handleFocus = () => { if (focusedIndex !== index) { setFocusedIndex(index); } }; return ( 
  • {item.label}
  • ); }
    Nach dem Login kopieren

    Remarquez que c'est la balise a qui devrait avoir la ref (bouton pour l'élément de menu avec sous-menus), donc lorsqu'ils sont ciblés, les comportements par défaut du clavier entreront en vigueur comme prévu, comme la navigation sur Entrée. De plus, l'index des onglets est correctement attribué en fonction de l'élément ciblé.

    Nous ajoutons un gestionnaire d'événements pour l'événement focus au cas où l'événement focus ne proviendrait pas d'un événement clé/souris. Voici une citation du web doc :

    Ne présumez pas que tous les changements de focus se produiront via des événements de touche et de souris : les technologies d'assistance telles que les lecteurs d'écran peuvent définir le focus sur n'importe quel élément focalisable.

    Ajustement n°1

    Si vous suivez l'useEffect décrit ci-dessus, vous constaterez que le premier élément aura le focus même si l'utilisateur n'a pas utilisé le clavier pour naviguer. Pour résoudre ce problème, nous pouvons vérifier l'élément actif et appeler focus() uniquement lorsque l'utilisateur a démarré un événement clavier, ce qui détourne le focus du corps.

    useEffect(() => { if (linkRef.current && document.activeElement !== document.body // only call focus when user uses keyboard navigation && prevFocusedIndex !== focusedIndex && isCurrent) { linkRef.current.focus(); } }, [isCurrent, focusedIndex, prevFocusedIndex]);
    Nach dem Login kopieren

    Logic Reuse and Custom Hook

    So far, we have functional NavMenu and MenuItemLink components. Let's move on to menu item with sub menus.

    As I was quickly building it out, I realized that this menu item will share the majority of the logic

    Das obige ist der detaillierte Inhalt vonErstellen einer barrierefreien Navigationsmenüleiste mit React Hooks. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

    Quelle:dev.to
    Erklärung dieser Website
    Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
    Neueste Downloads
    Mehr>
    Web-Effekte
    Quellcode der Website
    Website-Materialien
    Frontend-Vorlage
    Über uns Haftungsausschluss Sitemap
    Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!