The Template Tag: A Refresher
on Web components, Template, Polyfills
The <template>
specification was introduced in 2011, along with the other three specs that make up WebComponents. Since then, <template>
has become a part of the W3C Living Document, and has full support in Chrome, Firefox, Opera, Safari, and Android. To boot, Edge has just announced upcoming support.
In light of that announcement, let’s refresh (:
Native Templates
Before the <template>
tag was introduced we still had templates, but to get them to work, we had to abuse existing functionality. The two most common techniques were:
- Hide the DOM off screen ```html
<ol start="2">
<li>Abusing the <code><script></code> tag</li>
</ol>
```html
<script id="simple-template" type="text/x-handlebars-template">
// My template's contents
</script>
Both of these techniques are not ideal. The first is clunky and can be accidentally modified by DOM manipulation. The latter exposes us to potential cross-site scripting attacks. The <template>
element seeks to solve these issues, and also provides additional benefits.
The Anatomy of a Template
The anatomy of a template is simple. It is any set of markup, styles, and javascript that is wrapped in <template>
tags. A template can even include another template! Here is a basic example:
<template id="simple">
<style>
span { color: purple; }
</style>
<img src="http://placehold.it/50x50" />
<span>Hello World!</span>
<script>
function boom(){
alert("BOOM!");
}
boom();
</script>
</template>
The Properties of a Template
Flexible placement
This code can live anywhere inside the <head>
or <body>
. It’s also important to note that you can place it as a child for a <select>
or <table>
element.
Inert
This means that the Javascript and CSS play no role in modifying the page. The code is not active until the template has been cloned and added to the page.
Hidden from CSS and Selectors
Your template’s content cannot be selected or modified with CSS or query selectors. This is to protect it from accidental changes, and for performance reasons.
But.. How do we use our template?
Chiggity-check this out:
function addSimple(){
// Grab our template
var t = document.querySelector('template#simple').content;
// Optional -- Modify template
// Clone and add
var clone = document.importNode(t, true);
document.getElementById("simple-target").appendChild(clone);
}
Simple enough. We’re:
- Grabbing a reference to our template’s content.
- We create a deep-copy clone of the template’s content
- and then we insert it into our existing DOM.
Simple Template Example
Notice that even though our span
style is defined in our template, it doesn’t affect the existing span
until it is cloned and added. Also, the JS is not executed until the template is added. Even the <image>
isn’t fetched pre-load. Basically, adding the template is like a live copy & paste into your DOM.
Can I data-bind? Data-binding is fun!
Nope. The closest we can get to this is using DOM manipulation techniques to change our templates to create “fake” data-binding. Here is a slightly more intense example that demonstrates this:
<form id="data-binding-form" onsubmit="return addRow()">
<label for="name-field">Name:</label>
<input type="text" name="name" id="name-field" />
<label for="age-field">Age:</label>
<input type="text" name="age" id="age-field" />
<label for="gender-field">Gender:</label>
<input type="text" name="gender" id="gender-field" />
<input type="submit" name="Submit" value="Submit"/>
</form>
<table id="persons-table">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Gender</th>
</tr>
</thead>
<tbody>
<tr>
<td>Chester Examplefield</td>
<td>92</td>
<td>Female</td>
</tr>
<!-- Our Row Template -->
<template id="table-row">
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</template>
<!-- End Row Template -->
</tbody>
</table>
Please Note:
- Our template is inside our table
- The template’s row is not visible on the screen
// ADD ROW
function addRow()
{
// Grab our template
var t = document.querySelector('template#table-row').content;
// Optional -- Modify template
var form = document.querySelector('#data-binding-form');
var age = form.querySelector("#age-field").value;
//var age = $("#data-binding-form #age-field"); // Equiv
var name = form.querySelector("#name-field").value;
var gender = form.querySelector("#gender-field").value;
t.querySelector("td:first-child").innerHTML = name;
t.querySelector("td:nth-child(2)").innerHTML = age;
t.querySelector("td:last-child").innerHTML = gender;
// Clone/activate template & add to page
var clone = document.importNode(t, true);
$("#persons-table tr:last").after(clone); // .after() is using jQuery
// Vanilla JS of .after();
//var allRows = document.querySelectorAll("table tr");
//var lastRow = allRows[allRows.length- 1];
//lastRow.parentNode.insertBefore(clone, lastRow.nextSibling);
return false; // Stop submit event from bubbling up
}
Please Note:
- We grab a reference to the template’s content
- We pull values from our form fields
- We update the template’s content with our values
- We clone the now modified template
- We add the clone to the page
“Data-Binding” Example
You get the idea. Not super intuitive, but it works. This is likely where we’ll see abstractions like polymer pick up the slack and introduce more developer friendly ways to do data-binding.
Support
Until we get full cross-browser support, it’s fairly safe to rely on Polyfills for <template>
as they’re simple and performant. Here are some examples of polyfill use:
- WebComponents.js (Google-Backed)
- Polyfill To Add IE Support
- Example Polyfill Use (IE6/7 Support)
Even so, unless your target browser support is IE11+, you probably shouldn’t be using <template>
in production. If anyone has any sources that show otherwise, please let me know! (:
Next Steps?
Templates lay the groundwork for the real meat and potatoes of WebComponents. To fully leverage their power, you may want to check out:
- Continuing your education on the
<template>
tag - Annnddd some more education
- Learning about Custom Elements (hint they use templates)
- Learn more about polyfills
Resources
- This article in Markdown format on GitHub
- “Simple Template” Example on GitHub
- “Data-Bind Template” Example on GitHub
- Track
<template>
s browser support
FAQ
Questions from this reddit thread and comments below will eventually be aggregated here