SKILL-04 — Tableaux et Listes de données¶
Listes, grilles, en-têtes et sémantique
Critères couverts¶
| Critère RAAM | Intitulé | Niveau | WCAG |
|---|---|---|---|
| 4.1 | Chaque tableau de données a un rôle de tableau | [A] | 1.3.1 |
| 4.2 | Les en-têtes de colonnes/lignes sont définis | [A] | 1.3.1 |
| 4.3 | Chaque cellule est associée à ses en-têtes | [A] | 1.3.1 |
| 4.4 | Le tableau a une description ou un résumé | [AA] | 1.3.1 |
Pourquoi c'est important¶
Impact utilisateurs
Dans un contexte mobile, l'espace d'écran limité rend les tableaux complexes. Les utilisateurs aveugles ou malvoyants peinent à lier mentalement une donnée à sa colonne/ligne sans la sémantique. Les défilements bi-directionnels (scroll vertical + horizontal) sont particulièrement difficiles pour ces profils.
Règle d'or
- Évitez les vrais tableaux visuels multi-colonnes. Préférez transformer chaque ligne en une carte détaillée (liste simple).
- Toujours grouper (combine) le contenu d'une cellule pour éviter que le lecteur d'écran lise des données morcelées.
- Annoncez explicitement les en-têtes.
Patterns¶
1. Liste Accessible [A]¶
✅ Bon — CollectionItemInfo + Label combiné
LazyColumn(modifier = Modifier.semantics {
collectionInfo = CollectionInfo(rowCount = users.size, columnCount = 1)
}) {
items(users.size) { index ->
Column(modifier = Modifier.semantics(mergeDescendants = true) {
collectionItemInfo = CollectionItemInfo(rowIndex = index, rowSpan = 1, columnIndex = 0, columnSpan = 1)
contentDescription = "${user.name}, ${user.job} chez ${user.company}"
}) {
Text(text = user.name)
Text(text = "${user.job} - ${user.company}")
}
}
}
2. Tableau de Données avec En-têtes [A]¶
✅ Bon — Sémantique manuelle et .isHeader
Grid {
GridRow {
Text("Nom").accessibilityAddTraits(.isHeader)
Text("Salaire").accessibilityAddTraits(.isHeader)
}
ForEach(employees) { emp in
GridRow {
Text(emp.name)
.accessibilityLabel("Nom: \(emp.name)")
Text(emp.salary)
.accessibilityLabel("Salaire annuel pour \(emp.name) : \(emp.salary)")
}
}
}
✅ Bon — heading() et CollectionItemInfo
Row {
Text("Nom", modifier = Modifier.semantics {
heading()
collectionItemInfo = CollectionItemInfo(rowIndex = 0, rowSpan = 1, columnIndex = 0, columnSpan = 1)
})
}
// Données...
Text(emp.name, modifier = Modifier.semantics {
collectionItemInfo = CollectionItemInfo(rowIndex = rowIndex, rowSpan = 1, columnIndex = 0, columnSpan = 1)
contentDescription = "Nom: ${emp.name}"
})
3. Tableau avec Description [AA]¶
4. Liste Groupée [A]¶
Checklist Audit Simplifié [A]¶
- Les listes simples sont construites avec les composants natifs (
List,LazyColumn). - Les éléments de listes multi-colonnes regroupent leur texte pour une lecture fluide (combine/mergeDescendants).
- Les en-têtes de colonnes/lignes sont marqués sémantiquement.
- Les cellules rappellent leur contexte d'en-tête (le lecteur d'écran ne se perd pas).
- Si un tableau de données complexe est présenté, une version "vue en liste" ou CSV est proposée en alternative.
Checklist Audit Complet [AA]¶
- Le tableau/grille de données possède une description globale de son objectif.
- Dans les listes groupées, les séparateurs sont marqués explicitement comme en-têtes.
- Le tableau respecte le contraste minimum pour ses bordures (≥ 3:1).
- Les cellules interactives (boutons, liens) ont une zone de clic d'au moins 44x44 points (iOS) ou 48x48 dp (Android).
Outils¶
| Outil | Plateforme | Usage |
|---|---|---|
| VoiceOver | iOS | Tester le balayage dans la grille pour vérifier l'association cellule-en-tête |
| TalkBack | Android | Idem, vérifier la lecture des infos de collection |