Skip to content
AgileLogics
5 min read

The template Element

Prerequisites: How the HTML parser works

A template holds markup that isn't rendered. Its content is parsed into a separate, inert DocumentFragment: images inside don't load, scripts don't run, and querySelector on the document doesn't find it. JavaScript clones it when needed.

<template id="product-row">
  <li class="product">
    <img alt="" width="48" height="48">
    <span class="name"></span>
    <span class="price"></span>
  </li>
</template>

<ul id="products"></ul>

<script>
  const products = [
    { name: "Rye loaf", price: 4.2, img: "rye.jpg" },
    { name: "Spelt <new>", price: 3.8, img: "spelt.jpg" },
  ];
  const tpl = document.getElementById("product-row");
  const list = document.getElementById("products");

  console.log("in document:", document.querySelectorAll(".product").length);

  for (const p of products) {
    const row = tpl.content.cloneNode(true);
    row.querySelector("img").src = p.img;
    row.querySelector(".name").textContent = p.name;
    row.querySelector(".price").textContent = `£${p.price.toFixed(2)}`;
    list.append(row);
  }

  console.log("in document:", document.querySelectorAll(".product").length);
  console.log(list.lastElementChild.querySelector(".name").outerHTML);
</script>
in document: 0
in document: 2
<span class="name">Spelt &lt;new&gt;</span>
  • tpl.content is the fragment; cloneNode(true) makes a deep copy.
  • Filling the copy with textContent keeps user data safe.
  • Nothing inside the template was fetched until it was cloned into the page — the empty img never made a request.

Templates can go anywhere

The parser allows template in places where other elements can't go — inside a table, select, or head — and parses its content as if it were in the right context:

<table>
  <tbody id="rows">
    <template id="row-tpl"><tr><td class="c"></td></tr></template>
  </tbody>
</table>
<script>
  const row = document.getElementById("row-tpl").content.firstElementChild;
  console.log(row.tagName, row.firstElementChild.tagName);
</script>
TR TD

Trying the same with a div would foster-parent the row out of the table.

Where templates are used

  • Client-side rendering without a framework.
  • Web components — the next lessons.
  • Declarative shadow DOM, which uses <template shadowrootmode>.
  • Frameworks compile their own template syntax (Vue's <template>, Angular, Svelte) — similar idea, different mechanism.

Related developer tools