Start · Sprachen · JavaScript · Referenz · HTMLTemplateElement

HTMLTemplateElement

Schnittstelle

Stellt ein <code>&lt;template&gt;</code>-Element dar, dessen inaktiver Inhalt über <code>content</code> als <code>DocumentFragment</code> zum Klonen bereitsteht.

seit JavaScript Baseline: alle Browser (seit 2015); shadowRootMode Kategorie: webapi

Signatur

interface HTMLTemplateElement extends HTMLElement

Beschreibung

Das Interface HTMLTemplateElement steht für das HTML-Element <template>. Dessen Inhalt wird vom Parser zwar eingelesen, aber nicht dargestellt und nicht ausgeführt: Bilder werden nicht geladen, Skripte laufen nicht, und Selektoren wie document.querySelector() finden die Kindelemente nicht. Der Inhalt liegt stattdessen in einem eigenen, inaktiven DocumentFragment, das über die Eigenschaft content erreichbar ist.

Templates eignen sich gut für wiederkehrende UI-Bausteine wie Listeneinträge, Tabellenzeilen, Karten oder Dialoge. Das übliche Vorgehen: den Inhalt mit template.content.cloneNode(true) oder document.importNode(template.content, true) klonen, im Klon die Daten eintragen (am besten über textContent) und den Klon anschließend ins DOM einfügen. Das ist sicherer und oft schneller als HTML-Strings über innerHTML zusammenzubauen.

Zusammen mit Web Components ist <template> das Standardmittel, um das Markup eines Shadow DOM festzulegen. Mit dem Attribut shadowrootmode (Eigenschaft shadowRootMode) kann der Parser sogar direkt einen deklarativen Shadow Root erzeugen, ganz ohne JavaScript.

Wichtige Eigenschaften:

  • content (nur lesbar): DocumentFragment mit dem Inhalt des Templates.
  • shadowRootMode: spiegelt das Attribut shadowrootmode wider ("open" oder "closed").
  • shadowRootDelegatesFocus, shadowRootClonable, shadowRootSerializable: weitere Optionen für deklarative Shadow Roots.

Rückgabewert

Typ
HTMLTemplateElement
Beschreibung
Instanzen bekommt man über den Parser, z. B. mit document.querySelector('template'), oder über document.createElement('template'). Einen eigenen Konstruktor gibt es nicht.

Beispiele

Template anlegen und Inhalt auslesen

// Template per Skript anlegen (statt im HTML)
const tpl = document.createElement('template');
tpl.innerHTML = '<li class="item"><span class="name"></span></li>';

console.log(tpl instanceof HTMLTemplateElement);
console.log(tpl.content instanceof DocumentFragment);
console.log(tpl.childNodes.length); // Kinder hängen am Fragment, nicht am Template selbst
console.log(tpl.content.firstElementChild.className);
true true 0 item

Liste aus Daten rendern (sicher per textContent)

// HTML:
// <template id="user-row">
//   <tr><td class="name"></td><td class="mail"></td></tr>
// </template>
// <table><tbody id="users"></tbody></table>

const users = [
  { name: 'Anna', mail: 'anna@example.com' },
  { name: 'Ben', mail: 'ben@example.com' }
];

const template = document.querySelector('#user-row');
const tbody = document.querySelector('#users');
const fragment = document.createDocumentFragment();

for (const { name, mail } of users) {
  const row = template.content.cloneNode(true);
  row.querySelector('.name').textContent = name; // kein XSS-Risiko
  row.querySelector('.mail').textContent = mail;
  fragment.append(row);
}

tbody.append(fragment); // nur ein DOM-Einfügevorgang
console.log(tbody.rows.length);
2

Template als Shadow DOM einer Web Component

const tpl = document.createElement('template');
tpl.innerHTML = `
  <style>:host { display: block; padding: .5rem; border: 1px solid #ccc; }</style>
  <strong><slot name="title">Ohne Titel</slot></strong>
  <p><slot></slot></p>
`;

class InfoCard extends HTMLElement {
  constructor() {
    super();
    const root = this.attachShadow({ mode: 'open' });
    root.append(tpl.content.cloneNode(true));
  }
}

customElements.define('info-card', InfoCard);

const card = document.createElement('info-card');
card.innerHTML = '<span slot="title">Hinweis</span>Template-Inhalt im Shadow DOM.';
document.body.append(card);
console.log(card.shadowRoot.querySelector('slot').name);
title

Deklarativer Shadow Root (shadowRootMode)

// HTML, wird vom Parser direkt in einen Shadow Root verwandelt:
// <my-box>
//   <template shadowrootmode="open"><p>Aus dem Template</p></template>
// </my-box>

const box = document.querySelector('my-box');
console.log(box.shadowRoot?.querySelector('p')?.textContent);

// Unterstützung prüfen
const supported = Object.hasOwn(HTMLTemplateElement.prototype, 'shadowRootMode');
console.log(supported);
Aus dem Template true

// Wichtig · Fallstricke

  • Immer klonen: Hängt man template.content direkt an (parent.append(template.content)), werden die Knoten verschoben. Danach ist das Template leer. Deshalb vorher cloneNode(true) oder document.importNode(content, true) verwenden.
  • Kinder liegen im Fragment: template.children ist leer, und document.querySelector('#tpl .x') findet nichts. Stattdessen template.content.querySelector() benutzen.
  • Nach dem Einfügen ist der Inhalt aktiv: Enthaltene <img>-, <script>- oder <iframe>-Elemente laden bzw. laufen, sobald der Klon im Dokument steckt. Wer unsichere Daten per innerHTML ins Template schreibt, öffnet damit eine XSS-Lücke. Nutzerdaten gehören über textContent oder setAttribute() in den Klon.
  • Skripte: Per innerHTML eingefügte <script>-Elemente werden grundsätzlich nicht ausgeführt. Aus einem Template geklonte Skripte laufen dagegen beim Einfügen, je nach Browser und Klonweg aber nicht immer zuverlässig. Darauf sollte man sich nicht verlassen.
  • Einsatz im Parser: <template> ist fast überall erlaubt, auch in <table>, <select> und <head>. Dadurch lassen sich z. B. <tr>-Vorlagen gültig notieren.
  • Kompatibilität: content wird von allen modernen Browsern unterstützt, im Internet Explorer fehlt es. Deklaratives Shadow DOM (shadowRootMode) gibt es in Chrome ab 111, Safari ab 16.4 und Firefox ab 123. shadowRootClonable und shadowRootSerializable sind noch neuer. Bei Bedarf per Feature-Erkennung prüfen.
  • Wird shadowrootmode nachträglich per JavaScript gesetzt oder das Template per innerHTML eingefügt, entsteht kein Shadow Root. Das klappt nur beim Parsen bzw. mit Element.setHTMLUnsafe() oder Document.parseHTMLUnsafe().