W3docs

Template-Element

Lerne, wie das HTML <template>-Element inerte, wiederverwendbare Markup-Strukturen speichert und wie du dessen Inhalt mit JavaScript klonst, um dynamische UIs effizient zu erstellen.

Das HTML-Element <template> ermöglicht es dir, einen Markup-Abschnitt auf deiner Seite zu deklarieren, den der Browser zwar parst, aber nicht rendert. Der Inhalt bleibt im Dokument bereit, inert, bis dein JavaScript ihn klont und in das Live-DOM einfügt. Damit ist <template> die idiomatische Methode, um eine „Vorlage" für wiederholte UI-Elemente zu definieren – Listenzeilen, Karten, Modal-Dialoge – ohne DOM-Knoten manuell aufzubauen oder HTML-Strings in innerHTML einzufügen.

Dieses Kapitel behandelt, was Template-Inhalt besonders macht, wie man ihn korrekt klont und einfügt, wie man Ereignisse auf geklonten Knoten verdrahtet, und die Fallstricke, die Erstbenutzer treffen. Templates sind auch ein Baustein von Web Components, wo sie natürlich mit Custom Elements und dem Shadow DOM zusammenpassen.

Das Template-Element verstehen

Das <template>-Element fungiert als Container für HTML-Inhalt, der nicht sofort gerendert wird. Die Schlüsselidee ist, dass sein Inhalt inert ist:

  • Es wird nicht angezeigt – das Markup wird niemals gerendert, unabhängig von CSS.
  • Seine Ressourcen werden nicht geladen<img>, <video> und <script> innerhalb eines Templates werden erst geladen oder ausgeführt, wenn der Inhalt in das Live-Dokument geklont wird.
  • Skripte darin werden nicht ausgeführt, und IDs darin kollidieren nicht mit dem Rest der Seite, bis sie aktiviert werden.

Das unterscheidet sich grundlegend davon, ein Element mit display: none zu verstecken. Ein Element mit display: none ist noch immer Teil des Live-DOM: Seine Bilder laden, seine Skripte laufen, und document.getElementById findet Elemente darin. Template-Inhalt lebt in einem separaten, DocumentFragment-gestützten Baum, sodass nichts davon passiert, bis du es durch Klonen aktivierst.

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

Templates für dynamischen Inhalt klonen

Ein Template ist nur eine Vorlage – es erzeugt allein keine sichtbare Ausgabe. Um es zu verwenden, liest du seine content-Eigenschaft (ein DocumentFragment), klonst dieses Fragment, füllst deine Daten ein und hängst den Klon an die Seite. Da du für jede Instanz klonst, kann ein Template beliebig viele unabhängige Kopien erzeugen, jede mit eigenen Daten.

Es gibt zwei Möglichkeiten zum Klonen:

  • template.content.cloneNode(true) – klont das Fragment direkt. Das Argument true bedeutet einen tiefen Klon (einschließlich aller Nachkommen); ohne es kopierst du nur das leere Fragment.
  • document.importNode(template.content, true) – führt denselben tiefen Klon durch, importiert die Knoten aber explizit in das aktuelle Dokument. Dies ist relevant, wenn das Template in einem anderen Dokument liegt (zum Beispiel Inhalt aus einem <iframe> oder <link rel="import">). Bei Templates im selben Dokument sind beide gleichwertig; importNode ist die sicherere Standardwahl.
Warnung

Klone stets den Template-Inhalt, bevor du ihn einfügst. Wenn du template.content direkt anhängst, verschiebst du die ursprünglichen Knoten aus dem Template in den DOM – das Template ist dann leer, und der nächste Klon erzeugt nichts. Durch Klonen bleibt die Vorlage für die Wiederverwendung erhalten.

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

Interaktivität mit JavaScript erweitern

Die content-Eigenschaft eines Templates gibt ein DocumentFragment zurück, das das inerte Markup enthält. Du kannst es abfragen und lesen (template.content.querySelector(...)), ohne die Live-Seite zu berühren. Ein saubereres Muster ist jedoch, zuerst zu klonen und dann Ereignisse am Klon zu verdrahten – so erhält jede Instanz ihre eigenen Listener. Für eine ausführlichere Behandlung des Anhängens von Handlern, siehe Event Handling im DOM.

Das folgende Beispiel definiert zwei Templates: einen Button und eine Inhalts-Karte. Ein Klick auf den Button klont das Karten-Template und hängt jedes Mal eine neue Kopie an.

<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 diesem Beispiel:

  • Wir haben zwei Templates: eines für einen Button (button-template) und eines für Inhalt (content-template).
  • Die Funktion insertButton klont das Button-Template und fügt es in den DOM ein. Außerdem hängt sie einen Event-Listener an den Button, der die Funktion displayTemplateContent beim Klicken aufruft.
  • Die Funktion displayTemplateContent klont das Inhalts-Template und fügt es jedes Mal, wenn der Button geklickt wird, in den DOM ein.
  • Der Button wird beim Laden der Seite durch den Aufruf von insertButton in den DOM eingefügt.

Wenn du also auf den Button „Try it yourself" klickst, siehst du einen Button mit der Beschriftung „Add a content card." Jedes Mal, wenn du darauf klickst, wird eine neue Karte aus dem Inhalts-Template zur Seite hinzugefügt, was das dynamische Einfügen durch Benutzerinteraktion demonstriert.

Häufige Fallstricke

Einige Fehlerquellen sind für die meisten Template-Bugs verantwortlich:

  • Vergessen zu klonen. Das direkte Anhängen von template.content leert das Template. Immer zuerst klonen.
  • Abfragen nach dem Anhängen. appendChild(clone) verschiebt die Knoten des Fragments in den DOM, sodass die Knoten des Klons zu Kindern des Ziel-Elements werden. Lese oder ändere den Klon (clone.querySelector(...)) bevor du ihn anhängst – danach ist das Fragment leer.
  • Doppelte IDs. IDs, die innerhalb eines Templates geschrieben sind, sind inert unproblematisch, aber sobald du es mehrfach klonst, trägt jede Kopie dieselbe ID – und doppelte IDs sind ungültiges HTML. Bevorzuge Klassen, data-*-Attribute oder bereichsbezogene Abfragen auf dem Klon statt document.getElementById für instanzspezifische Suchen.
  • Erwarten, dass Skripte ausgeführt werden. Ein <script> innerhalb eines Templates wird beim Klonen nicht ausgeführt, außer du erstellst es neu. Halte das Verhalten in deinem JavaScript, nicht im Template-Markup.

Browser-Unterstützung

Das <template>-Element ist Teil des HTML Living Standard und wird in jedem modernen Browser unterstützt (Chrome, Firefox, Safari, Edge). Für aktuelle Browser ist kein Polyfill erforderlich, was es zu einer sicheren, abhängigkeitsfreien Wahl für clientseitiges Templating macht.

Fazit

Das <template>-Element bietet dir eine native, framework-unabhängige Möglichkeit, wiederverwendbares Markup zu definieren und es bei Bedarf zu instanziieren. Da sein Inhalt bis zum Klonen inert ist, vermeidet es das verschwendete Rendering und Ressourcenladen versteckter Elemente und umgeht die Sicherheits- und Parsing-Eigenheiten beim Aufbau von HTML aus Strings. Klone mit cloneNode(true) oder importNode, fülle den Klon aus, dann hänge ihn an – und du hast ein effizientes Muster, das von einer einzelnen Karte bis hin zu einem vollständigen Komponentensystem skaliert. Um Templates innerhalb einer vollständigen Komponente zu sehen, fahre mit Custom Elements und Web Components fort.

Übungen

Übung
Was ist der Hauptzweck des Template-Elements in JavaScript?
Was ist der Hauptzweck des Template-Elements in JavaScript?
Was this page helpful?