Le besoin
Quand une page comporte beaucoup d'information, il est parfois utile d'enfermer celles-ci dans un élément qui peut se déplier. Ce type de composant d'interface peut porter plusieurs noms : "expansion item", "expansion panel", "accordion"...
Voici un exemple de deux composants d'expansion utilisés à l'Université de Strasbourg pour l'offre de formation.

Les deux cadres où il est écrit le numéro de semestre et le nom du parcours cachent le contenu du semestre.

Quand les panneaux sont ouverts on voit des tableaux contenant la liste des matières et des unités d'enseignement liés au semestre.
Pour construire ce genre de composant, généralement on crée un bouton pour la partie cliquable de l'item et en dessous une div qui va cacher le contenu de l'expansion panel. Ensuite pour l'ouvrir, on va utiliser du Javascript qui va écouter le clic sur le bouton et changer le CSS du contenu pour "l'ouvrir". Ce système est encore utilisé aujourd'hui alors qu'il existe une balise HTML native qui permet de gérer complètement ce genre de composant manière native.
Construction
Pour construire un composant d'expansion, on va utiliser deux balises : details et summary.
details
Cette balise va servir à englober l'ensemble du composant. Il va porter l'état d'ouverture grâce à son attribut open qui ne sera présent que lorsqu'il est ouvert.
summary
Cette balise va être la partir cliquable de notre composant, celle qui habituellement est un button. Cette balise doit être dans un details pour fonctionner.
Exemple d'implémentation
Le HTML
Nous allons créer un composant un peu plus simple que l'exemple de l'Université de Strasbourg ci-dessus. Dans ce tutoriel, nous allons créer deux panneaux simples avec du texte random. Ils auront le marqueur d'ouverture sur la droite, le bouton d'ouverture aura un fond blanc presque transparent et des bordures seront ajoutées pour marquer les limites.
Mise en place de notre HTML :
<section>
<details>
<summary>Accordion item #1</summary>
<p>Accordion item #1 content</p>
</details>
<details>
<summary>Accordion item #2</summary>
<p>Accordion item #2 content</p>
</details>
</section>Ce qu'on peut voir sur ce code :
- Nous avons englobé nos deux panneaux d'une
sectionpour mettre de l'espace autour et gérer leur alignement. - Chaque
detailsa sonsummarypour permettre son ouverture. - Le contenu des
detailsest également à l'intérieur, sous lesummary. Ici nous avons desp, mais nous pourrions mettre ce que l'on veut et autant d'éléments que l'on souhaite. Par exemple, pour l'offre de formation, nous avons destable.
En mettant juste ce code de base nous avons un résultat qui est déjà fonctionnel ! Lorsque vous cliquez sur le summary d'un details, le contenu de ce dernier s'affiche et le marker à la gauche du summary pivote à 90°.
Le CSS
Pour faire les différentes choses dont ont a parlé ci-dessus, nous allons devoir faire un peu de CSS.
:root {
background-color: #121212;
}
body {
margin: 0;
color: white;
& section {
display: flex;
flex-direction: column;
align-items: flex-start;
& details {
border: 1px solid #fff;
width: 300px;
&:not(:last-child) {
border-bottom: none;
}
> * {
padding: 1rem;
}
&[open] {
& summary {
border-bottom: 1px solid #fff;
}
}
& summary {
background-color: rgba(255, 255, 255, 0.1);
cursor: pointer;
font-weight: bold;
}
& p {
margin: 0;
}
}
}
}On voit plusieurs choses :
- Je mets la
sectionenflexpour aligner correctement lesdetailsà gauche. - Je mets une bordure autour de chaque
details, mais j'enlève celle du bas sur toute, sauf sur la dernière =>details:not(:last-child). - J'ajoute une bordure en dessous des
summarypour séparer le bouton d'ouverture du contenu et je mets lepaddingsur lesummaryet les éléments de plus haut niveau dans le contenu pour avoir de l'espace par rapport à la bordure. Je ne l'ai pas mis sur ledetailscar sinon la bordure sous lesummaryn'irait pas jusque sur les côtés.
open". À l'heure où j'écris cet article, cet attribut est spécifique à l'élément details et à l'élément dialog. Il permet de sélectionner l'item quand le panneau est déplié.Avec tout ça on a toujours le marqueur d'ouverture à gauche. Dans notre cas d'usage, on voulait le marqueur sur la droite.
body {
//...
& section {
//...
& details {
//...
&[open] {
& summary {
//...
&::after {
transform: rotate(-90deg);
}
}
}
& summary {
&::marker {
content: "";
}
&::after {
content: "➤";
transform: rotate(90deg);
transition: transform 0.25s ease-in-out;
}
}
//...
}
}
}Pour supprimer le marqueur par défaut, on peut le sélectionner avec le pseudo-élément ::marker. Ici, je lui mets un content vide pour l'enlever et je le remplace par un pseudo-élément ::after. On ne peut pas utiliser directement le marqueur par défaut, car le fait de mettre le summary en flex, va cacher ce dernier.
Comme le caractère que j'utilise est tourné vers la droite, le lui applique une rotation à 90° pour qu'il soit tourné vers le bas, puis, quand le panneau est ouvert, je le tourne à -90° pour qu'il soit vers le haut et on ajout une transition pour avoir l'animation.
Nous avons maintenant un système de collapse panel complet et designé et vous connaissez maintenant cet élément de HTML peu connu.