W3docs

Elemento Template

Scopri come l'elemento HTML <template> memorizza markup inerte e riutilizzabile e come clonarne il contenuto con JavaScript per costruire UI dinamiche.

L'elemento HTML <template> ti permette di dichiarare un frammento di markup nella pagina che il browser analizza ma non visualizza. Il contenuto rimane pronto nel documento, inerte, finché il tuo JavaScript non lo clona e lo inserisce nel DOM live. Questo rende <template> il modo idiomatico per definire un "blueprint" per UI ripetute — righe di lista, card, finestre di dialogo modali — senza costruire nodi DOM a mano o incollare stringhe HTML in innerHTML.

Questo capitolo spiega cosa rende speciale il contenuto dei template, come clonarlo e inserirlo correttamente, come collegare eventi ai nodi clonati e le insidie più comuni per i nuovi utenti. I template sono anche un elemento fondamentale dei Web Components, dove si abbinano naturalmente agli elementi personalizzati e al Shadow DOM.

Comprendere l'Elemento Template

L'elemento <template> funge da contenitore per memorizzare HTML che non viene immediatamente visualizzato. Il concetto chiave è che il suo contenuto è inerte:

  • Non viene visualizzato — il markup non appare mai, indipendentemente dal CSS.
  • Le sue risorse non vengono caricate<img>, <video> e <script> all'interno di un template non vengono caricati né eseguiti finché il contenuto non viene clonato nel documento live.
  • Gli script al suo interno non vengono eseguiti e gli ID al suo interno non collidono con il resto della pagina finché non vengono attivati.

Questo è fondamentalmente diverso dal nascondere un elemento con display: none. Un elemento con display: none fa ancora parte del DOM live: le sue immagini vengono caricate, i suoi script vengono eseguiti e document.getElementById trova gli elementi al suo interno. Il contenuto del template vive in un albero separato basato su un frammento di documento, quindi nulla di tutto ciò accade finché non lo si opta attraverso la clonazione.

<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>

Clonare i Template per Contenuti Dinamici

Un template è solo un blueprint — da solo non produce alcun output visibile. Per utilizzarlo, si legge la sua proprietà content (un DocumentFragment), si clona quel frammento, si inseriscono i dati e si aggiunge il clone alla pagina. Poiché si clona per ogni istanza, un template può produrre tutte le copie indipendenti necessarie, ognuna con i propri dati.

Esistono due modi per clonare:

  • template.content.cloneNode(true) — clona il frammento in posizione. L'argomento true indica una clonazione profonda (inclusi tutti i discendenti); senza di esso si copierebbe solo il frammento vuoto.
  • document.importNode(template.content, true) — esegue la stessa clonazione profonda ma importa esplicitamente i nodi nel documento corrente. Questo è importante quando il template si trova in un documento diverso (ad esempio, contenuto importato tramite un <iframe> o <link rel="import">). Per i template dello stesso documento i due metodi sono equivalenti; importNode è la scelta più sicura per impostazione predefinita.
Attenzione

Clona sempre il contenuto del template prima di inserirlo. Se aggiungi template.content direttamente, sposti i nodi originali fuori dal template nel DOM — il template sarà poi vuoto e la successiva clonazione non produrrà nulla. La clonazione mantiene intatto il blueprint per il riutilizzo.

<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>

Migliorare l'Interattività con JavaScript

La proprietà content di un template restituisce un DocumentFragment che contiene il markup inerte. È possibile interrogarlo e leggerlo (template.content.querySelector(...)) senza toccare la pagina live, ma un pattern più pulito è clonare prima e poi collegare gli eventi al clone — in questo modo ogni istanza ottiene i propri listener. Per una trattazione più approfondita sull'attacco di handler, consulta Gestione degli eventi nel DOM.

L'esempio seguente definisce due template: un pulsante e una card di contenuto. Cliccando il pulsante si clona il template della card e si aggiunge una nuova copia ogni volta.

<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>

In questo esempio:

  • Abbiamo due template: uno per un pulsante (button-template) e uno per il contenuto (content-template).
  • La funzione insertButton clona il template del pulsante e lo inserisce nel DOM. Collega anche un event listener al pulsante per chiamare la funzione displayTemplateContent quando viene cliccato.
  • La funzione displayTemplateContent clona il template del contenuto e lo inserisce nel DOM ogni volta che il pulsante viene cliccato.
  • Il pulsante viene inserito nel DOM al caricamento della pagina chiamando insertButton.

Pertanto, quando si clicca sul pulsante "Try it yourself", si vedrà un pulsante con l'etichetta "Add a content card." Ogni volta che lo si clicca, viene aggiunta alla pagina una nuova card dal template di contenuto, dimostrando l'inserimento dinamico guidato dall'interazione dell'utente.

Errori Comuni

Alcune insidie sono responsabili della maggior parte dei bug con i template:

  • Dimenticarsi di clonare. Aggiungere template.content direttamente svuota il template. Clona sempre prima.
  • Interrogare dopo aver aggiunto. appendChild(clone) trasferisce il frammento nel DOM, così i nodi del clone diventano figli del target. Leggi o modifica il clone (clone.querySelector(...)) prima di aggiungerlo — dopo il frammento è vuoto.
  • ID duplicati. Gli ID scritti all'interno di un template vanno bene mentre sono inerti, ma una volta clonato più volte, ogni copia porta lo stesso ID — e gli ID duplicati sono HTML non valido. Preferisci classi, attributi data-* o query scoped sul clone piuttosto che document.getElementById per ricerche per istanza.
  • Aspettarsi che gli script vengano eseguiti. Un <script> all'interno di un template non viene eseguito al momento della clonazione a meno che non lo si ricrei. Mantieni il comportamento nel tuo JavaScript, non nel markup del template.

Supporto Browser

L'elemento <template> fa parte dell'HTML Living Standard ed è supportato in ogni browser moderno (Chrome, Firefox, Safari, Edge). Non è necessario alcun polyfill per i browser attuali, il che lo rende una scelta sicura e priva di dipendenze per il templating lato client.

Conclusione

L'elemento <template> ti offre un modo nativo e privo di framework per definire markup riutilizzabile e istanziarlo su richiesta. Poiché il suo contenuto è inerte fino alla clonazione, evita il rendering sprecato e il caricamento delle risorse degli elementi nascosti, e aggira le stranezze di sicurezza e parsing della costruzione di HTML da stringhe. Clona con cloneNode(true) o importNode, popola il clone, poi aggiungi — e hai un pattern efficiente che scala da una singola card a un intero sistema di componenti. Per vedere i template all'interno di un componente completo, continua con Elementi Personalizzati e Web Components.

Esercitazione

Pratica
Qual è lo scopo principale dell'Elemento Template in JavaScript?
Qual è lo scopo principale dell'Elemento Template in JavaScript?
Was this page helpful?