The template Element

Store inert HTML that you clone on demand with JavaScript.

The <template> element holds a chunk of markup that the browser parses but does not render or run. Images inside don't load, scripts don't execute — it's a dormant blueprint sitting in the DOM until you decide to use it.

Why it beats string concatenation

Before <template>, people built repeated UI by gluing HTML strings together, which is error-prone and unsafe. A template lets you author the markup normally, then clone it as many times as you need.

The pattern is always the same three steps:

  1. Grab the template's .content.
  2. Clone it with cloneNode(true).
  3. Fill in the clone and append it to the page.
const tpl = document.querySelector('#row');
const copy = tpl.content.cloneNode(true);
list.appendChild(copy);

This is the same cloning mechanism that powers list rendering in many frameworks — now you know what's underneath.

Example

Try it yourself
Loading editor…
Press Run to see the result.

When to use it

  • A web component uses <template> to define reusable card HTML that JavaScript clones and appends for each data item.
  • A table row template is stored in <template> and stamped out in a loop when the server returns JSON data.
  • A framework polyfill uses <template> to hold inert HTML that is activated only when the user triggers a modal.

More examples

Template cloned and appended by JS

content.cloneNode(true) copies the inert template; JavaScript fills data before appending it to the DOM.

Example · html
<template id="card-tpl">
  <div class="card">
    <h3 class="card-title"></h3>
    <p class="card-desc"></p>
  </div>
</template>

<div id="card-list"></div>

<script>
  const tpl = document.getElementById("card-tpl");
  const clone = tpl.content.cloneNode(true);
  clone.querySelector(".card-title").textContent = "HTML Basics";
  clone.querySelector(".card-desc").textContent = "Learn tags and structure.";
  document.getElementById("card-list").appendChild(clone);
</script>

Template for repeated list rows

A <template> for a table row is cloned once per data record to build the table body dynamically.

Example · html
<table>
  <thead><tr><th>Name</th><th>Score</th></tr></thead>
  <tbody id="scores"></tbody>
</table>

<template id="row-tpl">
  <tr><td class="name"></td><td class="score"></td></tr>
</template>

<script>
  const data = [{ name: "Alice", score: 95 }, { name: "Bob", score: 88 }];
  const tpl = document.getElementById("row-tpl");
  const tbody = document.getElementById("scores");
  data.forEach(({ name, score }) => {
    const row = tpl.content.cloneNode(true);
    row.querySelector(".name").textContent = name;
    row.querySelector(".score").textContent = score;
    tbody.appendChild(row);
  });
</script>

Template inside a web component

<template> stores the shadow DOM structure and scoped styles; a custom element clones it into its shadow root.

Example · html
<template id="hello-tpl">
  <style>p { color: teal; }</style>
  <p>Hello, <slot></slot>!</p>
</template>

<script>
  class HelloWorld extends HTMLElement {
    connectedCallback() {
      const shadow = this.attachShadow({ mode: "open" });
      const tpl = document.getElementById("hello-tpl");
      shadow.appendChild(tpl.content.cloneNode(true));
    }
  }
  customElements.define("hello-world", HelloWorld);
</script>

<hello-world>SoundsCode</hello-world>

Discussion

  • Be the first to comment on this lesson.