Panneau dépliant

Le paneau dépliant permet d'afficher ou de masquer du contenu supplémentaire via un clic sur un bouton. Contrairement à l'accordéon, le panneau dépliant ne fait pas partie d'une liste d'éléments identiques.

Règles d’implémentation pour l’accessibilité

  • Le titre du panneau dépliant est contenu dans un élément button avec un attribut aria-controls qui fait référence à l’id de l’élément qu’il contrôle et un attribut aria-expanded qui prend la valeur true quand la zone de contenu est visible et false quand la zone de contenu est masquée.
  • La zone de contenu détaillé du panneau a
    • un id avec la valeur de aria-controls du bouton qui permet de voir ou de masquer le contenu ;
    • un tabindex avec la valeur -1 quand le contenu est masqué afin de s’assurer que la prise de focus n’est pas possible ; la valeur de tabindex passe à 0 lorsque le contenu est affiché et le focus clavier est positionné sur le contenu affiché.
    • le rôle region. La région de rôle est particulièrement utile pour la perception de la structure par les utilisateurs de lecteurs d’écran lorsque les panneaux contiennent des éléments d’en-tête ou un accordéon imbriqué.

Visuel

Le contenu du panneau dépliant.

Extraits de code

Code HTML

L’attribut aria-label contiendra au départ le texte « Déplier » suivi du contenu de l’élément button.
Le script javascript présenté après remplacera le mot « Déplier » par « Replier » suivi du contenu de l’élément button afin que la vocalisation du bouton soit la plus précise possible (le contenu de aria-label est lu à la place du contenu du button).

<button type="button" class="depliant" aria-expanded="false" aria-controls="panno" aria-label="Déplier Panneau dépliant">
    Panneau dépliant
</button>
<div id="panno" role="region" tabindex="-1">
    <p>Le contenu du panneau dépliant.</p>
</div>

Code CSS

Pour adapter la couleur de la barre de navigation et des liens, modifier les codes couleurs dans la déclaration :root.
L’image d’arrière-plan utilisé pour symboliser la flèche est une icône de la police symbolique Fontawesome.

:root {
    --FRONT-color: #333;
    --BACKGROUND-color : #C3C3C3;
    --BACKGROUND-LIGHT-color: #E3E3E3;
    --FOCUS-color : #F9C233;
}
button.depliant {
  font-weight: normal;
  color: var(--FRONT-color);
  background-color: var(--BACKGROUND-color);
  border: 0;
  border-radius: .25em;
  white-space: nowrap;
  font-size: 1em;
  width: 100%;
  text-align: left;
  margin: 0.5em 0 0 0;
}
button.depliant::after {
  --icon-size: 1.25rem;
  content: "";
  background-color: currentColor;
  float: right;
  flex: 0 0 auto;
  height: var(--icon-size);
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  vertical-align: calc((0.55em - var(--icon-size)) * 0.5);
  width: var(--icon-size);
  -webkit-mask-image: url(../images/caret-right-fill.svg);
  mask-image: url(../images/caret-right-fill.svg);
  transform: rotate(90deg);
  transition: transform .2s ease-out;
}
button[aria-expanded=false].depliant  + div {
  display: none;
}
button[aria-expanded=true].depliant::after {
  transform: rotate(-90deg);
}
button[aria-expanded="true"].depliant {
  border-radius: .25em .25em 0 0 ;
}
button[aria-expanded=true].depliant + div {
  display: block;
  background-color: var(--BACKGROUND-LIGHT-color);
  overflow: auto;
  border-radius: 0 0 .25em .25em;
  padding: 1em;
}
button[aria-expanded=true],
button.depliant:focus,
button.depliant:hover {
  background-color: var(--FOCUS-color);
  outline: 3px solid var(--FOCUS-color);
  font-weight: bold;
  color: var(--BLACK-color);
  cursor: pointer;
}
button[aria-expanded="false"].depliant,
button.depliant + div   {
  margin-bottom: 1.5em;
}
button.depliant  + div:focus {
  outline: 3px solid var(--FOCUS-color);
}
button.depliant  + div a:focus{
  outline: 0  ;
}

Code javascript

/************ Panneau dépliant ***********/
function PlierDeplier() {

  var lesButtons = document.querySelectorAll('button.depliant');
  var i;
  for (i = 0; i < lesButtons.length; i++) {
      // apparition/disparition du sous-menu au clic
      lesButtons[i].addEventListener('click', function (e) {
          var leBouton = e.target;
          var lePanneau = leBouton.nextElementSibling;
          for (j = 0; j < lesButtons.length; j++) {
              if (leBouton !== lesButtons[j]) 
              lesButtons[j].setAttribute('aria-expanded', 'false')
          }        
          var stateButton = leBouton.getAttribute('aria-expanded') === 'false' ? true : false;
          leBouton.setAttribute('aria-expanded', stateButton);
          var textBoutonDeplier = "Déplier " + leBouton.innerText;
          var textBoutonReplier = "Replier " + leBouton.innerText;
          var labelButton = leBouton.getAttribute('aria-expanded') === 'false' ? textBoutonDeplier : textBoutonReplier;
          leBouton.setAttribute('aria-label', labelButton);
          var indexPanneau = leBouton.getAttribute('aria-expanded') === 'false' ? -1 : 0 ;
          lePanneau.setAttribute('tabindex', indexPanneau);
          lePanneau.focus();
      });
  }
}
if (document.querySelectorAll('button.depliant')) {
  PlierDeplier();
}