How to use the template tag in HTML5 with clear examples

Last update: November 12th 2025
  • It allows you to define inert content that is cloned and activated on demand.
  • It is accessed via .content and inserted with importNode/cloneNode for controlled rendering.
  • Declarative Shadow DOM with shadowrootmode encapsulates styles and structure without JS.
  • Combine templates with a good HTML5 boilerplate and metadata for SEO/social.

Templates with the template tag in HTML5

If you develop in frontend, sooner or later you'll encounter the `<template>` tag as a key tool for composing and reusing interface fragments without cluttering the DOM or incurring rendering costs. It's the bridge between traditional HTML and modern dynamics where content is injected with JavaScript.

Previously, most templates resided on the server (PHP, Ruby, Python, etc.). Today, we can build reusable structures in the browser using engines like Mustache, Handlebars, Nunjucks, or even custom logic with Web Components , and the `<template>` element has become the ideal base: inert content, ready to be cloned when needed.

What is the template tag and why is it so useful?

The `<template>` tag defines a snippet of HTML that the browser parses but doesn't render or execute until you activate it. This means you can prepare a UI block (a table row, a user card, an article) and only "render" it when needed.

In practice, the template content is not part of the active document: it doesn't appear in the rendered tree and doesn't affect the layout, trigger image loads, or execute scripts . Everything remains dormant within the JavaScript `template.content` property until you clone and insert that content.

Key features of

To fully understand how it behaves, it's helpful to review its distinctive features and how they affect the page flow, as each feature is designed to control the execution and rendering of the UI.

  • The content is parsed by the browser, but it is not drawn; it remains invisible and does not take up space.
  • It is inert: nothing within the template runs or loads (scripts, images, audio or video) until you activate it.
  • It does not belong to the main document: a document.getElementById() or querySelector() on document does not find its internal nodes; You must access via template.content.
  • You can place it in head, body, or frameset, with any valid HTML inside; its versatility It allows you to design complex templates without penalizing the initial rendering..

Browser compatibility and how to detect support

Support for the `<template>` tag has been available in modern browsers for some time: Chrome, Firefox, Safari, Opera, and current mobile browsers handle it without issue; the notable absence is Internet Explorer, which never implemented the tag . Support was rolled out gradually in older versions (Firefox 22+, Chrome 26+, Safari 7.1+, Opera 15+, iOS 8+, Android 4.4+, etc.).

To check if the environment properly supports the API, two lines of code are sufficient. The standard technique involves checking for the existence of the "content" property in a newly created template element :

if ("content" in document.createElement("template")) {
  // Soporte nativo disponible
} else {
  // Toca usar un polyfill o estrategia alternativa
}

Although native support is the norm by 2025, older browsers are still found in corporate environments; therefore, it is advisable to maintain defensive detection to avoid breaking the UI if the implementation is missing.

  Is it worth investing in legacy systems?

Create your first template with regular HTML

Defining a template is as simple as writing the HTML structure you want to reuse and wrapping it in a `<template>` tag. It's common practice to give it a descriptive ID so you can locate it later with JavaScript and keep the content as clean and semantic as possible.

<template id="plantilla-fila">
  <tr>
    <td></td>
    <td></td>
    <td></td>
  </tr>
</template>

In this example, the template describes a table row with three empty cells that we'll fill on the fly. You can place the template right after the table or even in the head section; it doesn't affect the layout until you clone and insert it.

Activate a template: importNode, cloneNode and .content

The `content` property exposes a `DocumentFragment` that contains everything within the template. To activate it, the usual method is to clone the fragment and attach it to the DOM. This is where `document.importNode()` (deep cloning) or, more directly, `template.content.cloneNode(true)` , which is concise and readable, comes into play.

const t = document.querySelector("#plantilla");
const fragmento = document.importNode(t.content, true);
fragmento.querySelector("h1").textContent = "Hola desde template";
document.body.appendChild(fragmento);

Alternatively, you can omit `importNode` and clone the fragment directly: `const clone = t.content.cloneNode(true)` . In both cases, the result is a tree ready for injection, which you can then customize with text, attributes, classes, or events before incorporating it into your document.

Practical example: completing a table with rows from a template

A classic example is generating table rows from a fixed header. You leave the header static and save the row structure in a `<template>`. Later, using JavaScript, you clone the row as many times as needed and add it to the end of the table, filling each cell with the appropriate data.

<table id="data">
  <tr>
    <th>Nombre</th>
    <th>Apellidos</th>
    <th>Calificación</th>
  </tr>
  <template id="user">
    <tr>
      <td>1</td>
      <td>2</td>
      <td>3</td>
    </tr>
  </template>
</table>

With the structure ready, simply clone the template content and insert it into the table. This pattern works the same with local data or when traversing remote JSON, because the resulting node is a standard DOM fragment that you can manipulate like any other element.

const table = document.querySelector("#data");
const userTemplate = document.querySelector("#user");
const clonedRow = userTemplate.content.cloneNode(true);
// Aquí podrías ajustar los textos de las celdas según tus datos
// clonedRow.querySelectorAll("td")[0].textContent = "Ada";
// clonedRow.querySelectorAll("td")[1].textContent = "Lovelace";
// clonedRow.querySelectorAll("td")[2].textContent = "10";
table.appendChild(clonedRow);

Repeat the process within a loop and you'll have your complete table in milliseconds. This approach keeps the HTML clean of logic and concentrates the dynamic part in the script, improving maintainability and performance.

Example of HTML5 template cloning

Declarative Shadow DOM with template: shadowrootmode

In addition to its classic use, `<template>` allows you to create a Shadow DOM declaratively using the `shadowrootmode` attribute. If you define it with `open` or `closed` within a container, the template's content is attached as a shadow tree, encapsulating styles and structure without requiring JavaScript.

<h2>Soy el título externo</h2>
<div class="container">
  <template shadowrootmode="open">
    <style>h2 { color: red; }</style>
    <h2>Soy el título interno</h2>
  </template>
</div>

Important details: With `shadowrootmode`, the template is no longer inert and is displayed immediately; internal styles only affect the shadow DOM, and external `h2` elements do not inherit that CSS . If you use `closed`, you will not be able to access the Shadow DOM from JavaScript, which increases isolation.

  Agile Software Development Methodology

This technique is ideal for isolating components and preventing style leaks. Use it when you need strong encapsulation and want to avoid dependencies on additional libraries or runtime, keeping the HTML as the source of truth.

Compatibility with IE and older browsers: HTML5Shiv and nuances

Internet Explorer did not implement `<template>` or its API. With HTML5Shiv (included in Modernizr) you can "present" unknown HTML5 elements, but note: this enables the element at the markup and style level, not the `.content` property or its inert behavior.

The practical difference is that, with shiv, the browser creates the element using `document.createElement()` and applies `display:none` by default. This can cause a brief flicker if the style changes, and, most importantly, you won't have the modern API to clone the fragment . For true support, you would need a template-specific polyfill or, alternatively, downgrade functionality.

Good practices for organization, performance and accessibility

Distribute templates near their intended use or in a dedicated section (for example, at the end of the body). Avoid nesting huge, unreadable templates; instead, use small, composable pieces that you can combine with JavaScript.

Use clear IDs (e.g., "tpl-card-product") and, if you need variants, use data attributes and classes. When cloning and inserting, adjust text with `textContent` and attributes with `setAttribute` to prevent XSS, especially if the data is coming from the server.

In terms of performance, remember that images within the `<template>` are not loaded until activation, which reduces the initial cost. However, if you're going to clone hundreds of nodes, do it in batches and upload the prepared fragment all at once to minimize repaints.

For accessibility, populate roles and aria-attributes after cloning if your pattern requires it (e.g., selectable rows, cards with buttons). And don't forget screen reader testing: new nodes must integrate with the DOM focus and order.

HTML5 boilerplate templates to start projects

The concept of a "boilerplate" describes repetitive sections of code that you use as a starting point. In HTML, a good boilerplate includes doctypes, language, essential meta tags, styles, and scripts; it saves you time and ensures consistency across pages.

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>HTML5 Boilerplate</title>
  <link rel="stylesheet" href="style.css" />
</head>
<body>
  <script src="index.js"></script>
</body>
</html>

The modern doctype (<!DOCTYPE html>) activates the browser's standard mode. The lang attribute in <html> helps with SEO and accessibility by indicating the primary language, facilitating correct pronunciation for screen readers.

  Ruby Programming: A Quick Start Guide for Beginners

`meta charset="UTF-8"` is the recommended encoding to support characters and symbols from virtually any language. `meta name="viewport"` adapts the width to the device and locks the zoom by default with `initial-scale=1`, key for responsive layouts.

The `meta http-equiv="X-UA-Compatible" content="ie=edge"` tag once indicated compatibility with IE; today its impact is minimal, but it still appears in some templates. Don't forget `<title>` with a descriptive title and a `<link rel="stylesheet">` to your main CSS.

Regarding scripts, by default place your references just before `</body>` to avoid blocking the render. When you need critical JS in the `<head>`, try to keep it lightweight, add `defer` where appropriate, and measure the effect on LCP and TTI.

Metadata for SEO and networks: Open Graph, Twitter Cards and icons

If your content is shared, it's a good idea to add Open Graph metadata and Twitter Cards. These fields enrich the preview (title, description, image), which can improve click-through rates on social media and messaging apps, as well as provide context for search engines.

<meta property="og:title" content="Template HTML5 básico" />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://www.ejemplo.com/pagina" />
<meta property="og:description" content="Template HTML5 para proyectos" />
<meta property="og:image" content="/images/ogimage.png" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="@tuusuario" />
<meta name="twitter:creator" content="@autoria" />

Complete the visual identity with favicons and an Apple Touch icon, including SVG and PNG variants for different contexts. These elements are small, but they lend professionalism and consistency to the brand, especially on mobile devices and browser tabs.

One extra note: demos and resources

If you want to see a complete workflow with `<template>` and dynamic cloning, there are public examples on CodePen, such as sergiodxa's: https://codepen.io/sergiodxa/pen/EaNwVz. Paying attention to how they organize the HTML, cloning JS, and node manipulation will help you adopt solid patterns from the start.

Working with the template tag in HTML5 allows you to elegantly separate structure and data, activate content when needed, and encapsulate it if you require a Shadow DOM— all with a positive impact on performance, maintainability, and code cleanliness . Combined with a good boilerplate and well-defined metadata, you'll have a modern foundation for scalable projects where your UI is built on demand without surprises.