Avancé20 min de lecture

Template & Composants Web

Apprends à utiliser l'élément template pour créer des fragments HTML réutilisables, et découvre le Shadow DOM et les éléments personnalisés pour construire des composants web.

L'élément <template>

L'élément <template> contient du contenu HTML qui n'est pas affiché au chargement de la page. Il sert de modèle que tu peux cloner et insérer dans le DOM avec JavaScript.

html
<template id="card-template">
  <div class="card">
    <h3 class="card-title"></h3>
    <p class="card-body"></p>
  </div>
</template>

Caractéristiques clés :

  • Le contenu à l'intérieur de <template> est inerte — les images ne se chargent pas, les scripts ne s'exécutent pas, les styles ne s'appliquent pas.
  • Le contenu se trouve dans un DocumentFragment accessible via template.content.
  • Tu le clones avec template.content.cloneNode(true) pour créer une copie active.

C'est beaucoup plus propre que de construire des éléments DOM entièrement en JavaScript ou d'utiliser innerHTML.

Utiliser les Templates en JavaScript

Voici le schéma pour utiliser un template :

js
// 1. Récupère le template
const template = document.getElementById('card-template');

// 2. Clone le contenu
const clone = template.content.cloneNode(true);

// 3. Remplis les données
clone.querySelector('.card-title').textContent = 'Ma Carte';
clone.querySelector('.card-body').textContent = 'Description de la carte ici.';

// 4. Ajoute au DOM
document.getElementById('card-container').appendChild(clone);

Tu peux cloner le template autant de fois que nécessaire — chaque clone est indépendant. C'est ainsi que tu construis des listes dynamiques, des grilles de cartes, ou tout motif d'interface répété.

L'élément <slot> et le Shadow DOM

L'élément <slot> est utilisé à l'intérieur du Shadow DOM pour créer des points d'insertion où le contenu du light DOM apparaît.

Les bases du Shadow DOM

Le Shadow DOM encapsule la structure interne d'un composant. Les styles et le balisage à l'intérieur d'un arbre shadow ne s'échappent pas, et les styles externes n'entrent pas.

js
class MyCard extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'open' });
    shadow.innerHTML = `
      <style>
        .card { border: 1px solid #333; padding: 1rem; }
      </style>
      <div class="card">
        <slot name="title">Titre par défaut</slot>
        <slot>Contenu par défaut</slot>
      </div>
    `;
  }
}
customElements.define('my-card', MyCard);

Utilisation :

html
<my-card>
  <h3 slot="title">Titre personnalisé</h3>
  <p>Ceci va dans le slot par défaut.</p>
</my-card>
  • Les slots nommés (<slot name="...">) acceptent les éléments avec un attribut slot correspondant.
  • Le slot par défaut (sans nom <slot>) capture tout le contenu non assigné.
  • Le texte entre les balises <slot> est un contenu de secours affiché quand aucun contenu n'est fourni.

Shadow DOM Déclaratif

Traditionnellement, le Shadow DOM nécessite JavaScript. Le Shadow DOM Déclaratif te permet de définir des arbres shadow directement en HTML en utilisant un <template> avec shadowrootmode :

html
<my-card>
  <template shadowrootmode="open">
    <style>
      .card { border: 1px solid #444; padding: 1rem; }
    </style>
    <div class="card">
      <slot name="title">Titre par défaut</slot>
      <slot>Contenu par défaut</slot>
    </div>
  </template>
  <h3 slot="title">Titre rendu côté serveur</h3>
  <p>Ça fonctionne sans JavaScript !</p>
</my-card>

C'est particulièrement utile pour le rendu côté serveur (SSR) — l'arbre shadow est attaché immédiatement pendant l'analyse HTML, sans besoin de JavaScript pour le rendu initial.

Exemple de Clonage de Template

html
<!-- Template : non affiché, juste un modèle -->
<template id="item-template">
  <li class="item">
    <strong class="item-name"></strong>
    <span class="item-desc"></span>
  </li>
</template>

<!-- Conteneur pour les éléments clonés -->
<ul id="item-list"></ul>

<script>
  const template = document.getElementById('item-template');
  const list = document.getElementById('item-list');
  const items = [
    { name: 'HTML', desc: 'Structure' },
    { name: 'CSS', desc: 'Style' },
    { name: 'JS', desc: 'Comportement' },
  ];

  items.forEach(item => {
    const clone = template.content.cloneNode(true);
    clone.querySelector('.item-name').textContent = item.name;
    clone.querySelector('.item-desc').textContent = ' — ' + item.desc;
    list.appendChild(clone);
  });
</script>

Que se passe-t-il avec le contenu à l'intérieur d'un élément <template> au chargement de la page ?

Prêt à pratiquer ?

Crée ton compte gratuit pour accéder à l'éditeur de code interactif, lancer les défis et suivre ta progression.