Accordion

Réaliser un "expansion panel" ou accordéon avec des éléments HTML natifs.

Auteur :
Jonathan Marco
Difficulté :
Initiation au rêve (débutant)

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 section pour mettre de l'espace autour et gérer leur alignement.
  • Chaque details a son summary pour permettre son ouverture.
  • Le contenu des details est également à l'intérieur, sous le summary. Ici nous avons des p, 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 des table.

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;
            }
        }
    }
}
J'utilise ici un version "nested" de CSS. Elle est disponible sur les navigateurs avec le moteur chromium à partir de la version 112, sur safari depuis la version 16.5 et Firefox depuis la version 117, page dédiée sur canIUse.

On voit plusieurs choses : 

  • Je mets la section en flex pour aligner correctement les details à 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 summary pour séparer le bouton d'ouverture du contenu et je mets le padding sur le summary et 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 le details car sinon la bordure sous le summary n'irait pas jusque sur les côtés.
Tout ce qu'on voit plus haut est générique. Le seul élément ici qui est particulier est le fait de sélectionner par rapport à l'attribut "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.

Code final

Cliquez pour télécharger le code final

  • Cours
  • Tutoriels
  • Aide
  • À Propos