W3docs

L'élément Template

Apprenez comment l'élément HTML <template> stocke un balisage inerte et réutilisable, et comment cloner son contenu avec JavaScript pour créer des interfaces dynamiques.

L'élément HTML <template> vous permet de déclarer un fragment de balisage dans votre page que le navigateur analyse mais ne pas affiche. Le contenu reste disponible dans le document, inerte, jusqu'à ce que votre JavaScript le clone et l'insère dans le DOM actif. Cela fait de <template> la manière idiomatique de définir un « modèle » pour une interface répétée — lignes de liste, cartes, boîtes de dialogue modales — sans construire de nœuds DOM manuellement ni coller des chaînes HTML dans innerHTML.

Ce chapitre couvre ce qui rend le contenu des templates spécial, comment le cloner et l'insérer correctement, comment câbler des événements sur les nœuds clonés, ainsi que les pièges qui guettent les nouveaux utilisateurs. Les templates sont également un composant de base des Web Components, où ils s'associent naturellement aux éléments personnalisés et au Shadow DOM.

Comprendre l'élément Template

L'élément <template> agit comme un conteneur pour stocker du HTML qui n'est pas immédiatement rendu. Ce qui rend son contenu inerte est l'idée clé :

  • Il n'est pas affiché — le balisage n'est jamais peint, quel que soit le CSS.
  • Ses ressources ne sont pas récupérées<img>, <video> et <script> à l'intérieur d'un template ne se chargent ni ne s'exécutent tant que le contenu n'est pas cloné dans le document actif.
  • Les scripts qu'il contient ne s'exécutent pas, et les IDs à l'intérieur n'entrent pas en conflit avec le reste de la page tant qu'ils ne sont pas activés.

C'est fondamentalement différent de masquer un élément avec display: none. Un élément avec display: none fait toujours partie du DOM actif : ses images se chargent, ses scripts s'exécutent, et document.getElementById trouve les éléments à l'intérieur. Le contenu d'un template vit dans un arbre séparé, soutenu par un fragment de document, donc rien de tout cela ne se produit jusqu'à ce que vous optiez pour le cloner.

<body>
  <div>You won't see the template, as it's not activated using JS.</div>
  <div id="template-container">
    <template id="my-template">
      <h1>Hidden!</h1>
    </template>
  </div>
</body>

Cloner les Templates pour du Contenu Dynamique

Un template n'est qu'un plan — il ne produit aucune sortie visible par lui-même. Pour l'utiliser, vous lisez sa propriété content (un DocumentFragment), clonez ce fragment, remplissez vos données, et ajoutez le clone à la page. Comme vous clonez pour chaque instance, un seul template peut produire autant de copies indépendantes que nécessaire, chacune avec ses propres données.

Il y a deux façons de cloner :

  • template.content.cloneNode(true) — clone le fragment sur place. L'argument true signifie un clone profond (inclure tous les descendants) ; sans lui, vous ne copierez que le fragment vide.
  • document.importNode(template.content, true) — effectue le même clone profond mais importe explicitement les nœuds dans le document courant. Cela est important lorsque le template réside dans un document différent (par exemple, du contenu importé via une <iframe> ou <link rel="import">). Pour les templates dans le même document, les deux sont équivalents ; importNode est la valeur par défaut la plus sûre.
Avertissement

Clonez toujours le contenu du template avant de l'insérer. Si vous ajoutez template.content directement, vous déplacez les nœuds originaux hors du template dans le DOM — le template est alors vide et le prochain clone ne produit rien. Le clonage laisse le plan intact pour une réutilisation.

<head>
  <style>
    .card {
      border: 1px solid #ccc;
      border-radius: 5px;
      padding: 10px;
      margin: 10px;
      width: 200px;
    }
    .card h3 {
      margin: 0;
    }
  </style>
</head>
<body>
  <div id="template-container">
    <!-- Template element -->
    <template id="card-template">
      <div class="card">
        <h3 id="card-title">Title</h3>
        <p id="card-content">Content goes here...</p>
      </div>
    </template>
  </div>

  <div id="card-container">
    <!-- Cards will be inserted here -->
  </div>

  <script>
    // Data for multiple cards
    const cardData = [
      { title: 'Card 1', content: 'This is the first card.' },
      { title: 'Card 2', content: 'This is the second card.' },
      { title: 'Card 3', content: 'This is the third card.' }
    ];

    // Function to create and insert cards
    function createCards(data) {
      const template = document.getElementById('card-template');

      data.forEach(item => {
        const clone = document.importNode(template.content, true);

        // Customize the cloned content
        clone.querySelector('#card-title').textContent = item.title;
        clone.querySelector('#card-content').textContent = item.content;

        // Insert the cloned content into the DOM
        document.getElementById('card-container').appendChild(clone);
      });
    }

    // Create cards with the provided data
    createCards(cardData);
  </script>
</body>

Améliorer l'Interactivité avec JavaScript

La propriété content d'un template retourne un DocumentFragment qui contient le balisage inerte. Vous pouvez l'interroger et le lire (template.content.querySelector(...)) sans toucher à la page active, mais le modèle le plus propre consiste à cloner d'abord, puis à câbler les événements sur le clone — de cette façon, chaque instance obtient ses propres écouteurs. Pour une couverture plus approfondie de l'attachement de gestionnaires, consultez La gestion des événements dans le DOM.

L'exemple ci-dessous définit deux templates : un bouton et une carte de contenu. Cliquer sur le bouton clone le template de la carte et ajoute une nouvelle copie à chaque fois.

<body>
  <div id="template-container">
    <!-- Button Template -->
    <template id="button-template">
      <button id="show-content-btn">Add a content card</button>
    </template>

    <!-- Content Template -->
    <template id="content-template">
      <div class="content">
        <h2>Dynamic Content</h2>
        <p>This content is added dynamically when the button is clicked.</p>
      </div>
    </template>
  </div>

  <div id="button-container">
    <!-- Button will be inserted here -->
  </div>

  <div id="content-container">
    <!-- Content will be displayed here -->
  </div>

  <script>
    // Function to display template content
    function displayTemplateContent() {
      // Get the content template
      const contentTemplate = document.getElementById('content-template');
      // Access the .content property and clone it
      const contentClone = document.importNode(contentTemplate.content, true);

      // Display the cloned content
      document.getElementById('content-container').appendChild(contentClone);
    }

    // Insert the button template into the DOM
    function insertButton() {
      // Get the button template
      const buttonTemplate = document.getElementById('button-template');
      const buttonClone = document.importNode(buttonTemplate.content, true);

      // Add event listener to the button
      buttonClone.querySelector('#show-content-btn').addEventListener('click', displayTemplateContent);

      // Insert the button into the DOM
      document.getElementById('button-container').appendChild(buttonClone);
    }

    // Call the function to insert the button when the page loads
    insertButton();
  </script>
</body>

Dans cet exemple :

  • Nous avons deux templates : un pour un bouton (button-template) et un pour le contenu (content-template).
  • La fonction insertButton clone le template du bouton et l'insère dans le DOM. Elle attache également un écouteur d'événement au bouton pour appeler la fonction displayTemplateContent lors d'un clic.
  • La fonction displayTemplateContent clone le template de contenu et l'insère dans le DOM à chaque clic sur le bouton.
  • Le bouton est inséré dans le DOM au chargement de la page en appelant insertButton.

Ainsi, lorsque vous cliquez sur le bouton « Try it yourself », vous verrez un bouton intitulé « Add a content card ». Chaque fois que vous cliquez dessus, une nouvelle carte provenant du template de contenu est ajoutée à la page, démontrant une insertion dynamique pilotée par l'interaction utilisateur.

Pièges Courants

Quelques écueils sont à l'origine de la plupart des bogues liés aux templates :

  • Oublier de cloner. Ajouter template.content directement vide le template. Clonez toujours en premier.
  • Interroger après l'ajout. appendChild(clone) vide le fragment dans le DOM, donc les nœuds du clone deviennent des enfants de la cible. Lisez ou modifiez le clone (clone.querySelector(...)) avant de l'ajouter — après, le fragment est vide.
  • IDs en double. Les IDs écrits à l'intérieur d'un template sont corrects tant qu'ils sont inertes, mais une fois que vous le clonez plusieurs fois, chaque copie porte le même ID — et les IDs en double constituent du HTML invalide. Préférez les classes, les attributs data-*, ou des requêtes scoped sur le clone plutôt que document.getElementById pour les recherches par instance.
  • S'attendre à ce que les scripts s'exécutent. Un <script> à l'intérieur d'un template ne s'exécute pas lors du clonage, sauf si vous le recréez. Gardez le comportement dans votre JavaScript, pas dans le balisage du template.

Support des Navigateurs

L'élément <template> fait partie du standard HTML Living Standard et est pris en charge par tous les navigateurs modernes (Chrome, Firefox, Safari, Edge). Aucun polyfill n'est nécessaire pour les navigateurs actuels, ce qui en fait un choix sûr et sans dépendance pour le templating côté client.

Conclusion

L'élément <template> vous offre un moyen natif, sans framework, de définir un balisage réutilisable et de l'instancier à la demande. Parce que son contenu est inerte jusqu'au clonage, il évite le rendu inutile et le chargement de ressources des éléments cachés, et contourne les particularités de sécurité et d'analyse liées à la construction de HTML à partir de chaînes. Clonez avec cloneNode(true) ou importNode, peuplez le clone, puis ajoutez-le — et vous disposez d'un modèle efficace qui passe d'une seule carte à un système de composants entier. Pour voir les templates dans un composant complet, continuez avec les Éléments personnalisés et les Web Components.

Pratique

Pratique
Quel est le principal objectif de l'élément Template en JavaScript ?
Quel est le principal objectif de l'élément Template en JavaScript ?
Was this page helpful?