Aria-expanded : implémenter correctement les états dépliés
En Bref : L'essentiel à retenir
- aria-expanded indique si un élément contrôlant du contenu masquable est actuellement déplié (true) ou replié (false).
- L'attribut doit être sur l'élément déclencheur (bouton) et mis à jour dynamiquement avec JavaScript lors de chaque interaction.
- Combinez aria-expanded avec aria-controls pour lier le bouton au panneau contrôlé et hidden pour masquer le contenu replié.
- Un aria-expanded absent ou figé fait annoncer « réduit » un panneau pourtant ouvert : le lecteur d'écran décrit un état qui n'existe plus.
Les interfaces modernes regorgent d'éléments qui se déploient : accordéons, menus déroulants, panneaux de détails. Sans aria-expanded, les utilisateurs de lecteurs d'écran ne savent pas si un élément est ouvert ou fermé. Voici comment l'implémenter correctement.
Comprendre aria-expanded
aria-expanded est un attribut d'état ARIA qui communique si un élément dépliant est actuellement :
true: le contenu associé est visible/dépliéfalse: le contenu associé est masqué/replié- Non défini : l'élément n'a pas de comportement dépliant
Note
Un aria-expanded absent ou figé fait partie des défauts ARIA que l'on rencontre le plus souvent en audit : le composant s'ouvre visuellement, mais le lecteur d'écran continue d'annoncer « réduit ». Le WebAIM Million de février 2026 mesure d'ailleurs que les pages utilisant ARIA comptent en moyenne plus d'erreurs (59,1) que celles qui n'en utilisent pas (42).
Où placer l'attribut
L'attribut se place sur l'élément déclencheur (généralement un bouton), pas sur le contenu qui se déploie :
<!-- Correct : sur le bouton -->
<button aria-expanded="false" aria-controls="panel-1">
Voir les détails
</button>
<div id="panel-1" hidden>
Contenu du panneau...
</div>
<!-- Incorrect : sur le panneau -->
<button>Voir les détails</button>
<div aria-expanded="false">
Contenu du panneau...
</div>
Implémentation basique avec JavaScript
Voici un pattern complet pour un bouton dépliable :
<button
id="toggle-btn"
aria-expanded="false"
aria-controls="content-panel">
Afficher plus d'informations
</button>
<div id="content-panel" hidden>
<p>Contenu supplémentaire ici...</p>
</div>
const button = document.getElementById('toggle-btn');
const panel = document.getElementById('content-panel');
button.addEventListener('click', () => {
const isExpanded = button.getAttribute('aria-expanded') === 'true';
// Basculer l'état
button.setAttribute('aria-expanded', !isExpanded);
// Masquer/afficher le panneau
panel.hidden = isExpanded;
});
Ce duo bouton/panneau correspond au pattern de divulgation dont la fiche Contenu dépliable accessible donne le contrat complet (critères RGAA, clavier, ARIA).
Accordéon complet
Un accordéon avec plusieurs sections où une seule peut être ouverte :
<div class="accordion">
<h3>
<button aria-expanded="false" aria-controls="section-1">
Section 1
</button>
</h3>
<div id="section-1" class="panel" hidden>
Contenu de la section 1...
</div>
<h3>
<button aria-expanded="false" aria-controls="section-2">
Section 2
</button>
</h3>
<div id="section-2" class="panel" hidden>
Contenu de la section 2...
</div>
</div>
document.querySelectorAll('.accordion button').forEach(button => {
button.addEventListener('click', () => {
const isExpanded = button.getAttribute('aria-expanded') === 'true';
// Fermer toutes les sections
document.querySelectorAll('.accordion button').forEach(btn => {
btn.setAttribute('aria-expanded', 'false');
});
document.querySelectorAll('.accordion .panel').forEach(panel => {
panel.hidden = true;
});
// Ouvrir la section cliquée (si elle était fermée)
if (!isExpanded) {
button.setAttribute('aria-expanded', 'true');
document.getElementById(
button.getAttribute('aria-controls')
).hidden = false;
}
});
});
Consultez notre guide complet sur les accordéons accessibles pour les patterns clavier.
Menu déroulant navigation
Pour un menu de navigation avec sous-menus :
<nav>
<ul>
<li>
<button aria-expanded="false" aria-controls="submenu-1">
Produits
<svg aria-hidden="true"><!-- icône flèche --></svg>
</button>
<ul id="submenu-1" hidden>
<li><a href="/produit-a">Produit A</a></li>
<li><a href="/produit-b">Produit B</a></li>
</ul>
</li>
</ul>
</nav>
Astuce
Pour les menus, ajoutez la fermeture avec Échap et le clic extérieur pour une meilleure ergonomie.
Attributs complémentaires
aria-controls
Lie le bouton au panneau qu'il contrôle :
<button aria-expanded="false" aria-controls="details-panel">
Plus de détails
</button>
<div id="details-panel" hidden>...</div>
Le support de aria-controls est limité (principalement JAWS), mais c'est une bonne pratique de documentation du code.
hidden vs display: none
L'attribut HTML hidden est préférable à display: none en CSS car il est sémantique et compris par tous les navigateurs et technologies d'assistance.
<!-- Préféré -->
<div id="panel" hidden>...</div>
<!-- Alternative CSS si besoin d'animation -->
<div id="panel" class="collapsed">...</div>
Synchroniser l'icône visuelle
Si vous utilisez une icône pour indiquer l'état (flèche, +/-), masquez-la aux lecteurs d'écran :
<button aria-expanded="false">
Section FAQ
<svg aria-hidden="true" class="icon-chevron">
<!-- L'icône pivote via CSS selon l'état -->
</svg>
</button>
button[aria-expanded="true"] .icon-chevron {
transform: rotate(180deg);
}
L'information est déjà transmise par aria-expanded, l'icône est purement visuelle.
Erreurs courantes
1. Oublier de mettre à jour l'attribut
// Mauvais : l'état ARIA n'est jamais mis à jour
button.addEventListener('click', () => {
panel.classList.toggle('visible');
});
// Bon : l'état ARIA suit le visuel
button.addEventListener('click', () => {
const isExpanded = button.getAttribute('aria-expanded') === 'true';
button.setAttribute('aria-expanded', !isExpanded);
panel.hidden = isExpanded;
});
2. Utiliser aria-expanded sans contenu contrôlé
<!-- Incorrect : pas de contenu à déplier -->
<button aria-expanded="false">
Envoyer le formulaire
</button>
<!-- aria-expanded n'est pas adapté ici -->
N'utilisez aria-expanded que pour les éléments qui affichent/masquent réellement du contenu.
3. État initial incohérent
<!-- Incohérent : aria-expanded="true" mais contenu masqué -->
<button aria-expanded="true">Section</button>
<div hidden>Contenu...</div>
L'état ARIA doit toujours refléter l'état visuel réel.
Quand ne PAS utiliser aria-expanded
- Liens simples : un lien qui navigue vers une nouvelle page
- Boutons de soumission : formulaires classiques
- Onglets : utilisez plutôt
aria-selectedsur les tabs - Cases à cocher : l'état coché/non coché est déjà communiqué
Navigation clavier attendue
Pour un comportement conforme au pattern WAI-ARIA :
| Touche | Action |
|---|---|
| Entrée/Espace | Bascule l'état déplié |
| Flèche bas | (Optionnel) Ouvre et déplace le focus dans le panneau |
| Échap | Ferme le panneau et remet le focus sur le bouton |
button.addEventListener('keydown', (e) => {
if (e.key === 'Escape' &&
button.getAttribute('aria-expanded') === 'true') {
button.setAttribute('aria-expanded', 'false');
panel.hidden = true;
button.focus();
}
});
Test avec lecteur d'écran
Avec NVDA ou VoiceOver, le bouton doit être annoncé comme :
- "Afficher plus d'informations, bouton réduit" (quand fermé)
- "Afficher plus d'informations, bouton déplié" (quand ouvert)
Si vous n'entendez pas l'état, vérifiez votre implémentation.
Critères RGAA concernés
| Critère | Exigence |
|---|---|
| 7.1 | Scripts compatibles avec les technologies d'assistance |
| 7.3 | Composants accessibles au clavier |
| 10.8 | Changements de contexte non déclenchés automatiquement |
Conclusion
aria-expanded est essentiel pour rendre les interfaces dépliables accessibles. La clé : synchroniser l'état ARIA avec l'état visuel, et toujours placer l'attribut sur l'élément déclencheur. Testez avec un lecteur d'écran pour valider le comportement.
Vérifiez l'implémentation de vos composants interactifs avec RGAA Checker : notre outil analyse les attributs ARIA et détecte les incohérences.
Questions fréquentes
À quoi sert l'attribut aria-expanded ?
aria-expanded annonce si le contenu contrôlé par un élément est déplié, valeur true, ou replié, valeur false. Il se place sur le déclencheur et doit être mis à jour à chaque interaction, faute de quoi le lecteur d'écran annonce un état qui ne correspond plus à ce que voit l'utilisateur.
Sur quel élément placer aria-expanded ?
Sur l'élément qui déclenche l'ouverture, c'est-à-dire le bouton, et non sur le panneau qui s'ouvre. L'erreur inverse est fréquente et rend l'information inutile, puisque l'utilisateur entend l'état seulement après avoir atteint le contenu qu'il cherchait à déplier.
Quels attributs accompagner aria-expanded ?
aria-controls relie le bouton à l'identifiant du panneau qu'il commande, et l'attribut hidden retire réellement le contenu replié de l'arbre d'accessibilité. Un panneau seulement masqué visuellement reste lu par les lecteurs d'écran alors qu'il est annoncé comme replié.
Guides RGAA associés
Pour aller plus loin sur les sujets abordés dans cet article, consultez nos fiches techniques :
Chaque champ de formulaire doit avoir une étiquette (label) qui lui est liée explicitement.
Chaque image porteuse d'information doit avoir une alternative textuelle pertinente via l'attribut alt. Les images décoratives doivent avoir un attribut alt vide.
L'intitulé de chaque lien doit permettre de comprendre sa destination ou sa fonction, soit par l'intitulé seul, soit par l'intitulé complété par son contexte (phrase, titre de section, item de liste ou cellule de tableau).
Vidéos RGAA sur ce thème
Pour voir ces sujets en action, regardez les épisodes vidéo correspondants :
Articles similaires
Votre site est-il conforme ?
Ne prenez pas de risques avec l'accessibilité. Lancez un audit complet de votre site en quelques minutes et obtenez un rapport détaillé des corrections à apporter.