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 Argumenttruebedeutet 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;importNodeist die sicherere Standardwahl.
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
insertButtonklont das Button-Template und fügt es in den DOM ein. Außerdem hängt sie einen Event-Listener an den Button, der die FunktiondisplayTemplateContentbeim Klicken aufruft. - Die Funktion
displayTemplateContentklont 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
insertButtonin 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.contentleert 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 stattdocument.getElementByIdfü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.