Derek P. Collins
Product Designer & Developer

Using the HTML <template> element

I’ve often used JavaScript to create HTML fragments that I need to repeat and populate with dynamic data.

For example, let’s say that our data is an array of objects that contain a title, description, and a path to an image that we want to iterate over and turn into a series of cards within our HTML. Here’s an example of how that data might be modeled:

let data = [
  {
    "title": "An Example",
    "description": "This is just some example data.",
    "imagePath": "/path/to/image/example.jpg"
  }
  ...
]

Until recently, I would create these HTML fragments within JavaScript using the createElement() method:

const createCard = (data) => {
  let card = document.createElement('div');
  card.classList.add('card');
	
  let cardHeading = document.createElement('h1');
  cardHeading.innerHTML = data.title;
  card.appendChild(cardHeading);
	
  let cardDescription = document.createElement('p');
  cardDescription.classList.add('description');
  cardDescription.innerHTML = data.description;
  card.appendChild(cardHeading);
	
  let cardImage = document.createElement('img');
  cardImage.src = data.imagePath;
  card.appendChild(cardImage);
	
  return card;
}

However, I’ve now started using the <template> HTML element to create these fragments. Here’s what that would look like within the <body> of our HTML:

<!-- CARD TEMPLATE -->
<template id="card-template">
  <div class="card">
    <h1></h1>
    <p class="description"></p>
    <img />
  </div>
</template>

These HTML fragments aren’t rendered when the page is loaded – they’re only instantiated when they’re used.

You can then use this HTML template within your JavaScript by cloning it and populating it with your data:

const createCard = (data) => {
  // Get the template using the id
  let cardTemplate = document.getElementById('card-template');
	
  // Clone the template
  let cardClone = template.content.cloneNode(true);
	
  // Get the contents of the cloned template
  let card = cardClone.querySelector('.card');
	
  // Populate the contents of the cloned template with data
  card.querySelector('h1').innerHTML = data.title;
  card.querySelector('.description').innerHTML = data.description;
  card.querySelector('img').src = data.imagePath;
	
  return card;
}

The above, gets the card template using the id we assigned to it, clones it, and adds some dynamic data to the elements within the cloned template.

To take this a bit further, we can abstract cloning the template into a reusable JavaScript method:

const cloneTemplate = (id) => {
  let template = document.getElementById(id);
  let clone = template.content.cloneNode(true);
  return clone;
};

Then we can update our previous example accordingly:

const createCard = (data) => {
  let cardTemplate = cloneTemplate('card-template');
  let card = cardTemplate.querySelector('.card');
	
  card.querySelector('h1').innerHTML = data.title;
  card.querySelector('.description').innerHTML = data.description;
  card.querySelector('img').src = data.imagePath;
	
  return card;
}

I find this much easier to maintain than creating these HTML fragments within JavaScript directly.

Check out this example on CodePen for a fully working version of the above code.

<template> is compatible with the latest versions of all major desktop and mobile browsers.

Previous →