The <template> & <slot> elements
The <template> tag holds a chunk of HTML that is not shown when the page loads. JavaScript copies it with template.content.cloneNode(true) and inserts the copy wherever it is needed, such as one card per product. The <slot> tag is a placeholder inside a web component’s shadow DOM that gets filled with content supplied by the page.
Last updated: October 3, 2026
Quick facts
| Category | <template>: metadata, flow, phrasing and script-supporting content. <slot>: flow and phrasing content |
| Content model | <template>: nothing as visible children — its contents live in a separate document fragment (.content). <slot>: transparent |
| Tag omission | Neither the start nor the end tag can be omitted, for either element |
| Permitted parents | <template>: almost anywhere, including <head>, tables and lists. <slot>: any element that accepts phrasing content |
| DOM interfaces | HTMLTemplateElement, HTMLSlotElement |
Syntax
Live example
Edit the code below and watch the preview update instantly.
Attributes
<template>
| Attribute | Description |
|---|---|
| shadowrootmode | open or closed: turns the template into a declarative shadow root for its parent, with no JavaScript |
| shadowrootdelegatesfocus / shadowrootclonable / shadowrootserializable | Extra options for that declarative shadow root |
<slot>
| Attribute | Description |
|---|---|
| name | A named slot is filled by page content with a matching slot="name" attribute; an unnamed slot takes everything else |
Common examples
Rendering a list from data
Clone the template for each item, fill it in, then add it to the page.
Table rows
Templates are handy for <table> rows, because a <tr> can’t live inside a hidden <div>.
A web component with slots
In a custom element’s shadow DOM, <slot> marks where the page’s own content is placed.
<template> vs building HTML strings
A common shortcut is to build HTML in JavaScript with strings and innerHTML. It works, but if any data comes from users it can open the door to script injection (XSS), and long strings of HTML in JavaScript are hard to read.
With <template>, the markup stays in your HTML where it belongs, and you fill it in with textContent, which always treats data as plain text. It’s safer and easier to maintain, and cloning a template is fast.
| <template> + textContent | innerHTML strings | |
|---|---|---|
| Markup lives in | HTML | JavaScript |
| Safe with user data | Yes | Only if you escape it |
| Readability | Good | Gets messy |
Common mistakes to avoid
- Appending the template itself. Clone
template.contentwithcloneNode(true); the template element stays hidden. - Querying the template content with
document.querySelector. Its content isn’t in the page yet; search inside the clone instead. - Putting important content only in templates. Search engines may not see it until JavaScript renders it.
- Filling templates with
innerHTMLand user data. UsetextContentto avoid injection.
Accessibility & SEO tips
- Make sure content created from templates still uses proper elements — real buttons, links and headings — so it’s accessible.
- When you add content dynamically, consider an
aria-liveregion so screen reader users hear about updates. - For SEO-critical lists such as products or articles, render them in the HTML on the server rather than only through templates.
Browser support
Supported in all modern browsers, including Chrome, Edge, Firefox, Safari and their mobile versions. It was introduced with HTML5, and only very old browsers such as Internet Explorer 8 needed workarounds.