Les tableaux de données
Un tableau se lit de haut en bas et de gauche à droite — sauf quand on ne le voit pas. Lier chaque cellule à ses en-têtes, c'est rendre la grille lisible ligne à ligne. Démo, code, critères RGAA.
8 critères RGAA en jeu
Essayez-les
Un tableau simple
| Thématique | Critères conformes | Taux |
|---|---|---|
| Images | 7 sur 9 | 78 % |
| Couleurs | 3 sur 3 | 100 % |
| Formulaires | 9 sur 13 | 69 % |
Une double entrée : scope suffit encore
| Accueil | Contact | |
|---|---|---|
| Images | 2 | 0 |
| Formulaires | 0 | 4 |
Un tableau complexe : id et headers
| Accueil | Contact | |||
|---|---|---|---|---|
| Non conformes | Conformes | Non conformes | Conformes | |
| Images | 2 | 7 | 0 | 9 |
| Formulaires | 0 | 13 | 4 | 9 |
Ouvrez le mode tableau de votre lecteur d’écran — Ctrl +
Alt + flèches sur NVDA et JAWS — et parcourez les trois grilles cellule par cellule. À chaque changement de ligne ou de colonne, l'en-tête doit être réannoncé avant la valeur : « *Images, Taux, 78 %* », et non « *78 %* » seul. Réduisez ensuite la fenêtre à 320 pixels, puis tabulez : le troisième tableau déborde, et son cadre s'arrête au clavier pour qu'on puisse le faire défiler aux flèches.Cette démo existe aussi en page autonome.
L’erreur courante
Le tableau qui a l’air d’un tableau, et n’en est pas un pour le balisage.
<!-- À ne pas faire : rien ici n'est un en-tête -->
<table>
<tr>
<td><strong>Thématique</strong></td>
<td><strong>Taux</strong></td>
</tr>
<tr>
<td>Images</td>
<td>78 %</td>
</tr>
</table> Le gras fait un en-tête pour l’œil et pour personne d’autre. La première ligne
est une ligne de données comme les autres, et « 78 % » reste orphelin. <strong> dit l’importance, <th> dit la fonction — la fonction seule est
restituée.
Ce que coûte l’erreur se mesure à la lecture linéaire. L’œil recompose la grille en deux dimensions : il remonte à la colonne, revient à la ligne. Cellule par cellule, cette grille n’existe plus, il ne reste qu’une suite de valeurs. Dans un tableau de trois colonnes on compense en mémorisant la position ; dans un tableau de douze, on abandonne.
Deux variantes de la même erreur :
- Le titre écrit dans un
<p>ou un<h3>juste au-dessus du tableau, qu’aucuncaptionniaria-labelledbyne relie à lui. Il reste un paragraphe : qui arrive sur le tableau par la navigation entre tableaux ne l’entendra jamais. - Le tableau de mise en page qui, lui, emprunte
captionetthalors qu’il n’a aucune donnée à décrire, et annonce des étiquettes qui ne veulent rien dire.
Le code, pas à pas
1. Le titre : caption, à privilégier
<table>
<caption>Taux de conformité par thématique, audit de mars 2026</caption>
…
</table> Le critère 5.4 ne demande pas qu’un tableau ait un titre : il demande que le titre, s’il y en a un, soit associé au tableau. Un tableau qui n’en a aucun ne le fait pas échouer ; un titre visible non associé, si. Mettez-en un tout de même — c’est souvent la seule chose qu’on entend avant de décider d’entrer dans le tableau ou de passer.
Le glossaire « tableau de données ayant un
titre » admet quatre porteurs :
la balise caption, l’attribut title, aria-label, et aria-labelledby désignant un passage de texte placé avant ou après le tableau. Il ajoute que caption étant seule complètement supportée par les technologies d’assistance,
il est « fortement recommandé de privilégier cette solution ». C’est une
préférence appuyée, pas la règle : écrivez caption, et gardez aria-labelledby pour le titre qui doit rester hors du tableau.
caption doit être le premier enfant de <table> — placé après un <thead>, il est invalide et parfois ignoré. Et il dit ce que le tableau
contient, pas « Tableau 1 » : c’est le critère 5.5.
2. Les en-têtes : th, et scope pour dire ce qu’ils gouvernent
<thead>
<tr>
<th scope="col">Thématique</th>
<th scope="col">Taux</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Images</th>
<td>78 %</td>
</tr>
</tbody> scope="col" dit que l’en-tête gouverne toute sa colonne, scope="row" toute
sa ligne. La première cellule d’une ligne est souvent un en-tête elle aussi :
« Images » nomme la ligne, ce n’est pas une donnée — et c’est l’oubli le plus
fréquent.
Le glossaire « en-tête de colonne ou de
ligne » accepte une seconde forme
pour les en-têtes qui s’appliquent à la totalité d’une ligne ou d’une colonne :
une balise pourvue de role="columnheader" ou role="rowheader". Il recommande
dans la foulée de privilégier th, seul balisage totalement supporté. Écrivez
donc th — mais un tableau qui emploie le rôle n’est pas non conforme pour
autant, et le déclarer tel serait une fausse non-conformité.
3. Le tableau irrégulier : headers et id
La double entrée ne change rien. Tant que chaque en-tête gouverne toute sa ligne
ou toute sa colonne, scope suffit : scope="col" et scope="row" associent
l’un et l’autre à la cellule qui les croise, et c’est exactement ce que le test
5.7.1 accepte. headers posé là est du zèle — deux techniques concurrentes sur
la même grille, et autant d’occasions de casser une association en silence.
Le seuil est ailleurs : l’en-tête qui ne couvre pas toute une ligne ou toute
une colonne — en-têtes sur deux niveaux, cellules fusionnées. Sur celui-là, scope devient interdit (test 5.7.3) ; il porte un id unique, et chaque
cellule liste dans headers les id de tous ses en-têtes.
<thead>
<tr>
<td rowspan="2"></td>
<!-- Ces deux-là chapeautent deux colonnes chacun : un id, pas de scope -->
<th colspan="2" id="p-accueil">Accueil</th>
<th colspan="2" id="p-contact">Contact</th>
</tr>
<tr>
<th id="a-nc">Non conformes</th>
<th id="a-ok">Conformes</th>
<th id="c-nc">Non conformes</th>
<th id="c-ok">Conformes</th>
</tr>
</thead>
<tbody>
<tr>
<th id="t-images">Images</th>
<td headers="t-images p-accueil a-nc">2</td>
<td headers="t-images p-accueil a-ok">7</td>
<td headers="t-images p-contact c-nc">0</td>
<td headers="t-images p-contact c-ok">9</td>
</tr>
</tbody> Une fois headers choisi, tenez-le sur tout le tableau : les en-têtes de ligne
passent eux aussi à l’id seul. Mélanger scope ici et headers là ne cumule
rien d’utile.
La cellule vide en haut à gauche peut rester un <td> sans contenu : elle ne
nomme rien. Un <th> vide y est également admis et courant — ce qu’il ne faut
pas, c’est lui inventer un intitulé.
Dernier point, et c’est le piège qui survit aux copiés-collés : un id est
unique dans la page, pas dans le tableau. Deux tableaux dupliqués avec les
mêmes id d’en-tête associent les cellules du second aux en-têtes du premier.
4. Le résumé, pour un tableau complexe
Le critère 5.1 ne vise ni les tableaux denses ni les doubles entrées : il vise les tableaux de données complexes au sens du glossaire, ceux dont les en-têtes « ne sont pas répartis uniquement sur la première ligne et/ou la première colonne de la grille ou dont la portée n’est pas valable pour l’ensemble de la colonne ou de la ligne ». Une double entrée dont les en-têtes tiennent en première ligne et première colonne n’entre pas dans cette définition, et ne doit aucun résumé. Le tableau de la section précédente, lui, en doit un.
Le glossaire du résumé donne une seule technique
utilisable en HTML5 : l’écrire dans la balise caption, à la suite du titre, et
le masquer par CSS si nécessaire.
<caption>
Critères par thématique et par page auditée
<span class="resume">
Deux niveaux d'en-têtes en colonne : les pages auditées, puis pour chacune
le nombre de critères non conformes et conformes. Les thématiques sont en
première colonne.
</span>
</caption> L’attribut summary sur <table> reste accepté par le référentiel, qui le
mentionne pour les versions antérieures de HTML. Il est en revanche retiré de
HTML5, et les validateurs le signalent comme obsolète : ne l’écrivez pas dans du
code neuf, mais ne le déclarez pas non conforme dans du code ancien.
Un résumé visible profite d’ailleurs à tout le monde : la structure d’un tableau à deux niveaux d’en-têtes n’est évidente pour personne.
5. Ce qui rend ce résumé pertinent
Un résumé présent ne vaut rien par sa présence. Trois façons de l’écrire pour rien : redire le titre, commenter les données (« les images sont la thématique la plus en retard »), ou décrire l’apparence (« tableau à fond gris sur trois colonnes »). Aucune n’aide à se déplacer dans la grille.
<!-- À ne pas faire : présent, associé, et sans emploi -->
<span class="resume">Tableau des résultats de l'audit.</span> Le contrôle tient en une lecture : masquer le tableau, lire le résumé seul, et se demander si l’on saurait s’y déplacer. Un résumé utile dit combien de niveaux d’en-têtes il y a, ce qui est en ligne, ce qui est en colonne, et où sont les totaux quand il y en a.
Le raté le plus discret est le résumé recopié du tableau voisin : exact mot pour mot, faux pour celui-ci. Il coûte plus qu’une absence — on suit une structure qui n’est pas là avant de comprendre qu’on s’est perdu.
6. Le tableau de mise en page : l’exact inverse
Deux critères, deux exigences à ne pas confondre.
Le 5.3 en pose deux, et elles sont cumulatives : le contenu doit rester
compréhensible une fois linéarisé — lu cellule après cellule, ligne après ligne
— et la balise <table> doit porter role="presentation", ce qui la retire
de l’arbre d’accessibilité.
<!-- Une mise en page qui s'assume : le rôle, et rien d'un tableau de données -->
<table role="presentation">
…
</table> Le 5.8 exige, lui, l’absence de tout marquage de données : ni caption, ni th, ni thead, ni tfoot, ni summary, ni scope, ni headers, ni axis,
ni role="columnheader" ou role="rowheader". role="presentation" ne dispense
pas de les retirer : le test porte sur le balisage, pas sur ce que le navigateur
en fait à l’exécution.
La vraie réponse est ailleurs : ce tableau-là ne devrait pas exister. La grille et le flex font la mise en page sans mentir sur la nature du contenu.
Au clavier
Un tableau de données n’est pas interactif : il n’entre pas dans l’ordre de tabulation, et c’est normal. Sa navigation appartient au lecteur d’écran, qui offre un mode tableau dédié.
| Touche | Effet |
|---|---|
| Tab | Ne s’arrête pas sur les cellules — seulement sur les liens ou boutons qu’elles contiennent, et sur la zone de défilement quand il y en a une. |
| Ctrl + Alt + flèches | Déplace de cellule en cellule (NVDA, JAWS) ; l’en-tête est annoncé à chaque changement de ligne ou de colonne. |
| T | Va au tableau suivant de la page (mode navigation rapide). |
Si un tableau doit défiler horizontalement, la zone qui défile doit pouvoir
recevoir le focus — sinon son contenu devient inatteignable au clavier. Un tabindex="0" sur le conteneur suffit, à condition de lui donner un nom : role="region" et aria-labelledby pointant vers le titre du tableau.
Ce que le lecteur d’écran restitue
À l’arrivée sur le tableau : le titre, la nature et les dimensions — « Taux de conformité par thématique, audit de mars 2026, tableau à 3 colonnes et 4 lignes ». Puis, en circulant, chaque cellule est annoncée avec ses en-têtes : « Images, Taux, 78 % ». La formulation varie d’un lecteur à l’autre et selon ses réglages ; ce sont les informations qui doivent être là, pas ces mots-là.
Si vous n’entendez que « 78 % », le lien n’est pas établi — c’est le défaut du
critère 5.7. Et si vous n’entendez aucune annonce de tableau, c’est que les <th> manquent : le tableau est traité comme une mise en page.
Checklist
- Un titre associé au tableau : un
captionpremier enfant, ouaria-labelledbys’il doit rester hors du tableau. - Des
<th>pour les en-têtes de ligne et de colonne — jamais un<td>en gras. scope="col"/scope="row"tant que chaque en-tête gouverne toute sa ligne ou toute sa colonne, double entrée comprise.headers+id, sansscope, à partir des en-têtes sur plusieurs niveaux ou des cellules fusionnées.- Un résumé de structure dans le
caption, pour les seuls tableaux complexes au sens du glossaire. - Un résumé qui décrit ce tableau — pas son titre, pas ses chiffres, pas son allure.
- Un tableau de mise en page porte
role="presentation"et aucun marquage de données. - Une zone de tableau qui défile horizontalement prend le focus, et porte un nom.
Les critères RGAA en jeu
- Critère 5.4 — Titre de tableau associé
Le tableau porte un titre visible, et rien dans le code ne le relie au tableau. Le référentiel accepte caption, title, aria-label ou aria-labelledby, et recommande fortement caption — un paragraphe posé au-dessus n'est associé à rien.
- Critère 5.5 — Pertinence du titre de tableau
Le titre doit dire ce que le tableau contient. « Tableau 1 » est associé, mais ne renseigne personne.
- Critère 5.6 — En-têtes de tableau déclarés
Les en-têtes de ligne et de colonne existent à l'œil sans être déclarés : une cellule td mise en gras n'est pas un en-tête. Préférez th ; le référentiel admet aussi role=columnheader et role=rowheader quand l'en-tête couvre toute la ligne ou toute la colonne.
- Critère 5.7 — Association des cellules aux en-têtes
Chaque cellule doit être reliée à ses en-têtes : scope tant que chaque en-tête gouverne toute sa ligne ou toute sa colonne, headers et id à partir des en-têtes sur plusieurs niveaux ou des cellules fusionnées.
- Critère 5.1 — Résumé des tableaux complexes
Un tableau complexe au sens du glossaire — en-têtes hors de la seule première ligne ou première colonne, ou de portée partielle — se parcourt à l'aveugle sans un texte qui en décrit l'organisation.
- Critère 5.2 — Pertinence du résumé de tableau
Le résumé écrit une fois sert de gabarit au tableau suivant : présent, associé, mais décrivant une grille qui n'est plus celle-là — ou redisant simplement le titre.
- Critère 5.3 — Linéarisation des tableaux de mise en forme
Un tableau employé pour la mise en page doit vérifier deux conditions cumulatives : rester compréhensible une fois linéarisé, et porter role=presentation sur la balise table.
- Critère 5.8 — Mise en forme sans marquage de données
Le même tableau de mise en forme ne doit emprunter aucun marquage de données — caption, th, thead, tfoot, summary, scope, headers, axis — sous peine d'annoncer une grille qui n'existe pas.
Vérifiez votre composant avec l'extension
Pour aller plus loin
- Critère 5.7 — Association des cellules aux en-têtes : le test précis que passe un auditeur, et ce que notre outil sait en dire.
- Critère 5.1 — Résumé des tableaux complexes : où passe la frontière entre un tableau simple et un tableau qui doit un résumé.
- Les champs de formulaire : l’autre endroit où une association invisible décide de la lisibilité.
- Le glossaire du référentiel : « tableau de données complexe », « tableau de mise en forme », « en-tête de colonne ou de ligne » — les définitions qui tranchent les cas limites.
Sources
- W3C WAI — Tables Tutorial — du tableau simple au tableau irrégulier
- MDN —
<table>— la référence de l’élément - WCAG — Understanding 1.3.1 Info and Relationships — pourquoi la structure doit être programmatique
- DSFR — Tableau — l’implémentation de l’État français