⚡IntermediateHTML APIs and Web Components

The Template Element

Define reusable HTML fragments with <template> that are parsed but not rendered until cloned.

Overview

The <template> element holds HTML that is parsed and validated by the browser but not rendered it is inert. You can clone its content with JavaScript to stamp out multiple instances of a UI pattern efficiently. Before <template>, developers used techniques like innerHTML, hidden divs, or script tags with custom types to store HTML templates. The <template> element is the semantic, standards-based solution. Key characteristics: - The browser parses and validates the HTML inside <template> - The content is NOT rendered, executed, or displayed - Scripts inside don't run, images don't download, styles don't apply - You access the content via template.content (a DocumentFragment) - Clone with template.content.cloneNode(true)

Key Points

  • •<template> is parsed but invisible and inert scripts don't run, images don't load
  • •template.content returns a DocumentFragment containing the template's children
  • •cloneNode(true) deep-clones the fragment to create a new instance
  • •Templates can be named with an id for easy selection
  • •Good for repeating card/list item patterns stamped by JavaScript
  • •Templates are available anywhere in the document but conventionally in <head> or at end of <body>

Examples

Product card template

<!-- Template definition (not rendered) -->
<template id="product-card-tmpl">
  <li class="product-card">
    <img class="card-img" src="" alt="">
    <h3 class="card-name"></h3>
    <p class="card-price"></p>
    <button class="add-to-cart">Add to Cart</button>
  </li>
</template>

<!-- Target container -->
<ul id="product-list"></ul>

<script>
const tmpl    = document.getElementById('product-card-tmpl');
const list    = document.getElementById('product-list');

const products = [
  { id: 1, name: 'Widget Pro', price: '$29.99', img: 'w1.jpg' },
  { id: 2, name: 'Gadget X',   price: '$49.99', img: 'g1.jpg' },
];

products.forEach(product => {
  const clone = tmpl.content.cloneNode(true);  // deep clone
  clone.querySelector('.card-img').src     = product.img;
  clone.querySelector('.card-img').alt     = product.name;
  clone.querySelector('.card-name').textContent  = product.name;
  clone.querySelector('.card-price').textContent = product.price;
  list.appendChild(clone);
});
</script>

Notification toast template

<template id="toast-tmpl">
  <div class="toast" role="status" aria-live="polite">
    <span class="toast-message"></span>
    <button class="toast-close" aria-label="Dismiss">×</button>
  </div>
</template>

<div id="toast-container"></div>

<script>
function showToast(message) {
  const tmpl  = document.getElementById('toast-tmpl');
  const clone = tmpl.content.cloneNode(true);
  clone.querySelector('.toast-message').textContent = message;
  clone.querySelector('.toast-close').addEventListener('click', (e) => {
    e.target.closest('.toast').remove();
  });
  document.getElementById('toast-container').appendChild(clone);
}

showToast('File saved successfully!');
</script>

Common Mistakes

  • Trying to query elements inside <template> with document.querySelector the content is in a DocumentFragment, not the main DOM
  • Modifying the template itself instead of cloning first changes affect all future clones
  • Forgetting to deep clone with cloneNode(true) shallow cloning omits child nodes

Note

Use <template> over innerHTML for repeated UI patterns it's faster (no HTML parsing on each clone), avoids XSS when combined with textContent/setAttribute (never innerHTML on user data), and clearly separates markup from logic.

Exercises

Write HTML to solve each exercise. Use Preview to see it render in a live iframe, then mark as done.

Loading editor…

Completed: 0 / 5 exercises

Knowledge Check

Question 1 of 4

What is special about the HTML inside a <template> element?