Aller au contenu principal

Accessibilite Next.js : guide RGAA complet

Guide complet pour rendre vos applications Next.js accessibles selon le RGAA : SSR, App Router, next/image, gestion du focus et checklist.

21 min de lectureIntermediaire

1. Introduction : Next.js et les défis d'accessibilité

Next.js se distingue des applications React classiques par son architecture hybride. Contrairement à une SPA (Single Page Application) pure où tout le rendu est côté client, Next.js propose plusieurs stratégies de rendu : SSR (Server-Side Rendering), SSG (Static Site Generation), ISR (Incremental Static Regeneration) et streaming avec React Suspense.

Cette flexibilité est un atout pour la performance et le SEO, mais elle crée des situations complexes pour l'accessibilité. Quand le HTML est généré côté serveur, les technologies d'assistance reçoivent un document complet dès le chargement initial — c'est un avantage. Mais les navigations subséquentes sont gérées côté client par le router Next.js, ce qui signifie que les lecteurs d'écran ne sont pas informés du changement de page.

L'introduction de l' App Router dans Next.js 13 a modifié en profondeur la façon de structurer les applications. Les Server Components, les layouts imbriqués, les fichiers spéciaux (loading.tsx, error.tsx, not-found.tsx) et le streaming introduisent de nouveaux patterns qui ont chacun des implications pour l'accessibilité.

Le Pages Router, encore largement utilisé, présente d'autres défis : l'absence de metadata API native oblige à utiliser des packages tiers comme next-seo, et la gestion du focus entre les pages nécessite une configuration manuelle via le composant _app.tsx.

Enfin, le streaming (activé par défaut avec l'App Router et Suspense) fait apparaître le contenu progressivement. Si un lecteur d'écran commence à lire une page dont le contenu n'est pas encore entièrement chargé, l'utilisateur peut manquer des informations. Il est essentiel de signaler les états de chargement avec les attributs ARIA appropriés.

2. Erreurs d'accessibilité courantes en Next.js

Voici les problèmes d'accessibilité les plus fréquents dans les projets Next.js, et pourquoi ils posent problème.

2.1. next/image sans attribut alt pertinent

Le composantnext/imagerend l'attribut alt obligatoire en TypeScript, mais beaucoup de développeurs passent une chaîne vide (alt="") ou un texte générique ("image", "photo") pour supprimer l'erreur de compilation. Une image informative sans alternative textuelle pertinente est invisible pour les utilisateurs de lecteurs d'écran, ce qui viole le critère RGAA 1.1.

2.2. Attribut lang manquant ou incorrect sur la balise html

Dans l'App Router, l'attribut lang se définit dans le fichierapp/layout.tsxracine. Oublier cet attribut ou le définir de manière incohérente (par exemple "en" pour un contenu en français) empêche les lecteurs d'écran de prononcer correctement le texte. Un lecteur d'écran configuré en français qui rencontre un document déclaré en anglais va tenter de lire le texte avec une prononciation anglaise, rendant le contenu incompréhensible.

2.3. Layout shift perturbant les lecteurs d'écran

Les Cumulative Layout Shifts (CLS) ne sont pas seulement un problème de performance. Quand le contenu se déplace pendant le chargement (images sans dimensions, polices qui changent, composants chargés dynamiquement), les technologies d'assistance peuvent perdre le contexte. L'utilisateur qui naviguait dans une section se retrouve soudainement dans une autre partie de la page sans comprendre ce qui s'est passé. Next.js génère automatiquement les dimensions des images avec next/image, mais les composants chargés dynamiquement avecnext/dynamicsans placeholder peuvent provoquer des shifts importants.

2.4. Changement de route sans gestion du focus

C'est le problème d'accessibilité le plus critique et le plus ignoré dans les applications Next.js. Lors d'une navigation client-side (clic sur unnext/link), le contenu de la page change mais le focus reste sur le lien cliqué ou se perd complètement. Un utilisateur de lecteur d'écran ne reçoit aucune indication qu'une nouvelle page a été chargée. Il doit naviguer manuellement pour découvrir le nouveau contenu. C'est équivalent à ouvrir un livre à une nouvelle page sans le dire à quelqu'un qui ne voit pas.

2.5. Server Components et logique d'accessibilité

Les React Server Components ne peuvent pas utiliser d'état, d'effets ou de refs. Or, de nombreux patterns d'accessibilité nécessitent de la logique côté client : gestion du focus, toggle aria-expanded, trap du focus dans une modale, annonces live regions. L'erreur courante est de tenter d'implémenter ces patterns dans un Server Component, ce qui échoue silencieusement ou provoque une erreur de compilation. La solution n'est pas de tout transformer en Client Components, mais d'identifier précisément quelles parties de l'interface nécessitent de l'interactivité et de les isoler dans des composants marqués"use client".

3. Bonnes pratiques avec exemples de code

3.1. next/image avec texte alternatif

Le composant Image de Next.js optimise automatiquement les images (formats, tailles, lazy loading), mais l'accessibilité dépend entièrement de l'attribut alt que vous fournissez. Distinguez toujours les images informatives des images décoratives.

3.2. Metadata API pour des titres de page accessibles

Le titre de la page est le premier élément lu par un lecteur d'écran. Il doit être unique, descriptif et suivre un schéma cohérent. La Metadata API de Next.js (App Router) simplifie cette gestion avec l'export statique ou la fonction generateMetadata pour les pages dynamiques.

3.3. Gestion du focus au changement de route

Note : le Pages Router de Next.js incluait un route announcer intégré (next-route-announcer). L'App Router ne l'inclut pas encore — vous devez donc implémenter votre propre composant. Placez-le dans votre layout racine pour qu'il s'applique à toutes les navigations.

3.4. États de chargement accessibles avec loading.tsx

Le fichier loading.tsx de Next.js affiche automatiquement un fallback pendant le chargement d'une page. Pour que les technologies d'assistance informent l'utilisateur, utilisez aria-busy et une annonce live region.

3.5. Gestion d'erreur accessible avec error.tsx

Le fichier error.tsx capture les erreurs de rendu. L'erreur doit être annoncée aux technologies d'assistance et proposer une action de récupération accessible.

3.6. next/link et navigation client-side accessible

Le composant Link de Next.js effectue une navigation côté client (prefetching + changement de route sans rechargement complet). Pour l'accessibilité, assurez-vous que chaque lien a un intitulé explicite et que les liens ouvrant un nouvel onglet le signalent.

3.7. Server vs Client Components pour l'accessibilité

La règle est simple : gardez la structure sémantique HTML dans les Server Components et isolez la logique interactive dans les Client Components. Cela réduit la quantité de JavaScript côté client tout en conservant les patterns d'accessibilité nécessaires.

4. Critères RGAA clés pour Next.js

Parmi les 106 critères du RGAA 4.1.2, voici ceux qui sont particulièrement impactés par l'architecture Next.js et les choix techniques du framework.

1.1

Chaque image porteuse d'information a-t-elle une alternative textuelle ?

Thématique : Images

Le composantnext/imageexige un attribut alt en TypeScript, mais il faut s'assurer que le texte est pertinent et non générique. Les images décoratives doivent avoir alt="" et idéalement aria-hidden="true". Attention aux images générées dynamiquement (OG images, avatars) dont le alt est souvent oublié dans les templates.

8.1

Chaque page web est-elle définie par un type de document ?

Thématique : Éléments obligatoires

Next.js génère automatiquement le doctype HTML5 dans le rendu serveur. Ce critère est naturellement satisfait avec le framework. Cependant, vérifiez que votre configuration n'altere pas le rendu initial (certains middleware de transformation HTML peuvent corrompre le doctype).

8.2

Pour chaque page web, le code source généré est-il valide ?

Thématique : Éléments obligatoires

Next.js génère du HTML valide, mais les erreurs de balisage viennent souvent de votre code : balises p imbriquées dans des p (React transforme les div en p dans certains cas), attributs invalides, IDs dupliqués (fréquents avec les listes dynamiques sans clé unique). Utilisez le validateur W3C sur le HTML rendu côté serveur pour détecter ces problèmes.

8.3

Dans chaque page web, la langue par défaut est-elle présente ?

Thématique : Éléments obligatoires

Avec l'App Router, la langue se définit dansapp/layout.tsxsur la balise<html lang="fr">. Avec le Pages Router, utilisez le fichier_document.tsx. Pour les sites multilingues avecnext-intlouapp/[locale]/layout.tsx, vérifiez que le lang dynamique est toujours cohérent avec le contenu affiché.

12.1

Chaque ensemble de pages dispose-t-il d'au moins deux systèmes de navigation ?

Thématique : Navigation

Next.js ne fournit pas de système de navigation pré-construit. Vous devez implémenter au moins deux des mécanismes suivants : menu de navigation, plan du site, moteur de recherche. Le composant Link de Next.js facilite la navigation interne, mais c'est à vous de structurer le menu avec les rôles ARIA corrects (nav, role="navigation", aria-label) et de fournir un lien d'évitement vers le contenu principal.

12.7

Un lien d'évitement ou d'accès rapide à la zone de contenu principal est-il present ?

Thématique : Navigation

Le lien d'évitement ("Skip to main content") doit être le premier élément focusable de la page. Dans Next.js, placez-le dans le layout racine, juste après l'ouverture de<body>, avec un lien pointant vers l'ID de votre balise main. Utilisez les classes Tailwind sr-only et focus:not-sr-only pour le rendre visible uniquement au focus clavier.

5. Outils et packages recommandés

Un écosystème d'outils permet de détecter, tester et prévenir les problèmes d'accessibilité dans vos projets Next.js. Voici les indispensables.

Metadata API native (App Router)

Depuis Next.js 13+, l'exportmetadataou la fonctiongenerateMetadataremplacent avantageusement next-seo pour la gestion des titres, descriptions et balises Open Graph. La Metadata API est type-safe, supporte l'héritage (template de titre), et fonctionne nativement avec les Server Components.

Alternative Pages Router : next-seo

@axe-core/react

Détecte automatiquement les violations d'accessibilité pendant le développement. S'intègre dans la console du navigateur et signale les problèmes directement dans le DOM. Limitez son usage au mode développement pour ne pas impacter les performances en production.

@testing-library/react

La philosophie de Testing Library encourage les tests basés sur les rôles et les labels accessibles plutôt que sur les classes CSS ou les data-testid. Les queriesgetByRole,getByLabelTextetgetByAltTextvérifient implicitement que votre composant est accessible. Si votre test ne trouve pas l'élément, c'est probablement que votre HTML n'est pas sémantique.

pa11y-ci

Outil en ligne de commande qui teste l'accessibilité de vos pages dans un pipeline CI/CD. Configurez-le pour scanner toutes vos routes Next.js à chaque pull request. pa11y-ci peut être configuré avec un fichier de configuration listant les URLs à tester et les règles à appliquer. Combinez-le avec le sitemap généré par Next.js pour couvrir automatiquement toutes les pages.

6. Checklist accessibilité Next.js

Utilisez cette checklist pour vérifier l'accessibilité de votre application Next.js avant chaque mise en production.

Structure et configuration

  • L'attributlangest défini sur la balise<html>dans le layout racine
  • Chaque page a un titre unique via la Metadata API (export metadata ou generateMetadata)
  • Un lien d'évitement "Aller au contenu principal" est present dans le layout racine
  • La balise<main>a un ID (main-content) pour le lien d'évitement
  • La hiérarchie des titres (h1-h6) est logique et sans saut de niveau sur chaque page

Images et médias

  • Chaque composant next/image informatif a un attribut alt descriptif
  • Les images décoratives ont alt="" et aria-hidden="true"
  • Les dimensions width/height sont spécifiées pour éviter le layout shift

Navigation et routing

  • Le focus est déplacé vers le contenu principal à chaque changement de route
  • Le titre de la page est annoncé aux lecteurs d'écran lors des navigations client-side
  • Les liens next/link ont des intitulés explicites (pas de "cliquez ici" ou "en savoir plus" sans contexte)
  • Les menus de navigation utilisent la balise<nav>avec un aria-label descriptif

États de chargement et erreurs

  • Les fichiers loading.tsx utilisent role="status" et aria-busy="true"
  • Les fichiers error.tsx utilisent role="alert" et déplacent le focus vers le message d'erreur
  • Les fallbacks Suspense incluent un texte informatif (pas seulement un spinner visuel)
  • La page not-found.tsx propose des alternatives de navigation (lien accueil, recherche)

Interactivité et composants

  • Les éléments interactifs (modals, dropdowns, accordions) sont dans des Client Components avec la gestion du focus appropriée
  • Tous les éléments interactifs sont utilisables au clavier (Enter, Espace, Échap, flèches)
  • Les formulaires ont des labels associés avec htmlFor et des messages d'erreur liés par aria-describedby
  • Le piège du focus est évité : l'utilisateur peut toujours quitter un composant au clavier

Tests et CI/CD

  • @axe-core/react est configuré en mode développement
  • Les tests unitaires utilisent les queries accessibles de @testing-library/react (getByRole, getByLabelText)
  • pa11y-ci est intégré dans le pipeline CI pour scanner les routes principales
  • Des tests manuels avec un lecteur d'écran (VoiceOver, NVDA) sont effectués avant chaque release

Questions fréquentes

Next.js est-il accessible par defaut ?

Non. Next.js fournit des bases solides comme le rendu HTML cote serveur et la Metadata API, mais l'accessibilite depend entierement de votre implementation.

Faut-il utiliser next-seo ou la Metadata API native ?

Avec l'App Router, la Metadata API native couvre l'essentiel : title, description, canonical et Open Graph. next-seo n'est plus indispensable dans la majorite des cas.

Comment gerer le focus lors d'un changement de route en Next.js ?

Il faut deplacer le focus vers le contenu principal apres chaque navigation client-side, par exemple avec usePathname(), useEffect() et un element cible portant tabindex='-1'.

Les Server Components posent-ils des problemes d'accessibilite ?

Non par eux-memes. Les enjeux apparaissent surtout quand une logique interactive a11y doit etre geree cote client : focus, toggles, modales ou annonces live.

Le streaming SSR de Next.js affecte-t-il les lecteurs d'ecran ?

Oui, si vous n'annoncez pas correctement les etats de chargement. Utilisez aria-busy et des regions aria-live quand le contenu apparait progressivement.

next/image genere-t-il un attribut alt automatiquement ?

Non. Le composant exige un alt, mais ne genere ni la bonne alternative ni le bon niveau de detail a votre place.

Comment tester l'accessibilite d'une application Next.js ?

Combinez des tests automatises avec axe et testing-library, puis des verifications manuelles au clavier et avec un lecteur d'ecran.

Le middleware Next.js a-t-il un impact sur l'accessibilite ?

Indirectement oui, si vos redirections de langue ou de contexte rendent un contenu incoherent avec l'attribut lang de la page.

Testez l'accessibilite de votre application Next.js

RGAA Scanner detecte automatiquement les problemes d'accessibilite de votre site Next.js et genere un rapport detaille avec les criteres RGAA concernes.

Scanner mon site gratuitement