Un composant de carte produit doit accepter un titre différent à chaque utilisation, une image différente, parfois un bouton en plus. Écrire ce composant en dur avec des attributs pour chaque variante devient vite ingérable dès que la structure interne se complexifie. Les Web Components résolvent ce problème avec un DOM interne encapsulé, mais il leur faut un mécanisme pour laisser du contenu extérieur s'y glisser à des endroits précis.
La balise <slot> est ce mécanisme : un emplacement réservé dans le DOM d'un composant, où vient s'insérer du contenu fourni de l'extérieur.
Définition
<slot> marque, à l'intérieur du DOM fantôme (Shadow DOM) d'un composant personnalisé, l'endroit précis où le contenu placé par l'utilisateur du composant doit apparaître. Le composant définit sa structure interne, et délègue certains emplacements de cette structure à qui l'utilise, un peu comme un gabarit de lettre laisse des espaces vides à remplir.
Sans Shadow DOM actif, <slot> ne remplit aucun rôle de répartition de contenu : ce n'est pas une balise de mise en page générale, son mécanisme n'a de sens que dans le contexte précis des composants personnalisés. Cela ne la rend pas invisible pour autant : livrée à elle-même, elle affiche simplement son propre contenu, comme n'importe quel autre élément.
Emplacements nommés avec l'attribut name
Un composant simple n'a besoin que d'un slot par défaut, sans nom. Dès qu'il doit accueillir plusieurs zones de contenu distinctes, chaque <slot> reçoit un attribut name, et le contenu qui lui est destiné porte l'attribut slot avec la même valeur.
| Élément | Rôle |
|---|---|
<slot> sans name | Reçoit tout le contenu qui n'a pas d'attribut slot explicite |
<slot name="titre"> | Réserve un emplacement nommé titre |
Élément avec slot="titre" | Vient se placer dans le slot nommé titre, où qu'il apparaisse dans le HTML |
Exemple concret
Voici la définition minimale d'une carte, avec deux emplacements nommés pour le titre et l'image, plus un emplacement par défaut pour la description.
<template id="carte-produit">
<div class="carte">
<slot name="titre">Titre par défaut</slot>
<slot name="image"></slot>
<slot>Aucune description fournie</slot>
</div>
</template>
<carte-produit>
<h2 slot="titre">Casque sans fil</h2>
<img slot="image" src="casque.jpg" alt="Casque audio noir">
<p>Autonomie de 30 heures.</p>
</carte-produit>Le paragraphe de description n'a pas d'attribut slot : il atterrit donc dans le slot par défaut, sans nom. Le contenu de repli écrit à l'intérieur de chaque <slot>, comme Titre par défaut, ne s'affiche que si personne ne fournit de contenu pour cet emplacement.
Lien avec <template>
<template> et <slot> se complètent presque toujours dans un composant personnalisé : le premier définit un fragment de HTML inerte servant de gabarit, le second marque les trous à remplir dans ce gabarit une fois cloné et attaché au Shadow DOM. L'un sans l'autre a rarement d'intérêt : un template sans slot ne peut recevoir aucun contenu externe, et un slot en dehors de tout Shadow DOM ne répartit jamais aucun contenu externe, faute de composant hôte auquel se rattacher.
Placer un <slot> dans une page HTML ordinaire, en dehors de la définition d'un composant personnalisé, ne provoque aucune erreur, mais ne déclenche aucune répartition de contenu non plus : sans Shadow DOM auquel se rattacher, il n'y a aucun contenu externe à y insérer. La balise n'est pas masquée pour autant : elle affiche simplement, tel quel, ce qu'elle contient. C'est une source de confusion fréquente pour qui découvre la balise en testant un exemple isolé sans avoir défini de Shadow DOM : voir son contenu s'afficher peut laisser croire, à tort, que le mécanisme de slot a fonctionné.
Questions fréquentes
Slot fonctionne-t-il avec des frameworks comme React ou Vue ?Vue possède son propre système de slots, largement inspiré de cette balise mais géré par son moteur de rendu plutôt que par le navigateur. React n'utilise pas <slot> nativement et passe plutôt par la prop children, qui répond au même besoin avec une syntaxe différente.
slot nommé ?Oui, tous les éléments partageant le même attribut slot viennent se placer ensemble dans l'emplacement correspondant, dans leur ordre d'apparition dans le HTML d'origine. Rien n'impose qu'un slot nommé ne reçoive qu'un seul élément.
slot est vide en JavaScript ?La méthode assignedNodes() appelée sur l'élément slot renvoie la liste des nœuds qui lui ont été assignés. Une liste vide, une fois les nœuds de texte insignifiants écartés, signifie que le slot n'a reçu aucun contenu et affiche donc son contenu de repli. Cette vérification est utile pour adapter dynamiquement le composant, par exemple pour masquer un séparateur visuel quand la zone qu'il accompagne reste vide.