<template> Content template
Inert HTML that the page does not render, kept for scripts to clone.
The browser parses what is inside <template>, but it does not display it, run it or load anything from it. Scripts clone its content to build repeated items, like one row per product.
Images in a template stay undownloaded and scripts stay idle until the content is cloned into the page. Add shadowrootmode and the template creates a declarative shadow root for a web component.
The content fragment and declarative shadow roots are explained in the template element definition (opens in a new tab). In web components it works together with the slot element.
Syntax
<template id="name">
<p>Content to copy</p>
</template>When to use it
A row per search result, a card per product, a new line item each time the user clicks Add another: when a script stamps out repeated pieces from the same markup, keep that markup in a <template>. HTML in a template is much nicer to edit than HTML in JavaScript strings.
Content that is already on the page and only hidden for now, like an error message or the second step of a form, gets the hidden attribute. Template content is not part of the page at all until a script copies it. Template also has a second job. With shadowrootmode it gives a custom element its shadow tree right in the HTML.
Cloning copies every id inside the template. Three cards means three elements with the same id, and labels and fragment links break. Use classes in templates, or assign unique ids after cloning. Note too that document.querySelector cannot see inside a template; query its content. Template and the slot element often work as a pair.
Attributes
| Attribute | What it does |
|---|---|
shadowrootmode | open or closed: creates a declarative shadow root. |
shadowrootdelegatesfocus | Shadow root delegates focus. |
shadowrootclonable | Shadow root can be cloned. |
Live example
Edit the code and watch the preview.
<p>The template below is not shown:</p>
<template id="card">
<article>
<h2>Title</h2>
<p>Text</p>
</article>
</template>
<p>A script would copy it to build cards.</p>More examples
Row template inside a table
A template is allowed directly inside a tbody. That is handy for a row a script will copy for every new entry. You see the two real rows, and the template row stays invisible. It has classes instead of ids, so no two clones clash.
<table>
<thead>
<tr><th scope="col">Name</th><th scope="col">Email</th></tr>
</thead>
<tbody>
<tr><td>Ana</td><td>[email protected]</td></tr>
<tr><td>Ben</td><td>[email protected]</td></tr>
<template class="row-template">
<tr><td class="name"></td><td class="email"></td></tr>
</template>
</tbody>
</table>Scoped styles with a shadow root
Given shadowrootmode="open", the browser converts the template into a shadow root during parsing. No script is involved. Its style applies to that component only, and the paragraph outside looks exactly as before.
<info-box>
<template shadowrootmode="open">
<style>p{border:2px solid #36c;padding:.5em;border-radius:6px}</style>
<p><slot></slot></p>
</template>
Styles inside the shadow root stay inside.
</info-box>
<p>This paragraph has no border.</p>Tip: Keep markup that scripts copy over and over in a template.
Browser support
All current browsers support template, and it is in the HTML Living Standard (template support (opens in a new tab)).
Declarative shadow DOM, meaning the shadowrootmode attribute, arrived in every major browser in early 2024 (declarative shadow DOM support (opens in a new tab)). An older browser treats such a template as an ordinary one and keeps it invisible.
Accessibility
Cloned content has to be accessible once it is in the page. Check its labels, headings and focus handling, and announce dynamic updates where needed. How to announce them is covered in the W3C note Understanding Status Messages (opens in a new tab).
Common mistakes
Wrong
<template id="row" hidden>...</template>Right
<template id="row">...</template>The browser never displays template content. hidden adds nothing.
Frequently asked questions
How do I use the template tag with JavaScript?
Grab the template, clone its content and append the clone: const node = tpl.content.cloneNode(true); list.append(node);. Fill in text with textContent before inserting it, which is safer than building HTML strings. Anything inside <template> is parsed but inert, so images do not load, scripts do not run and nothing shows. Need a whole page and not a fragment? Start from one of the free HTML5 templates (opens in a new tab).
What is shadowrootmode on template?
It turns the template into declarative shadow DOM. Add shadowrootmode="open" (or closed) to a <template> inside an element, and the parser attaches a shadow root to that parent and moves the template content into it, no JavaScript involved. Web components can then render on the server and appear before any script loads.