Skip to content
Switch branches/tags
Go to file
Cannot retrieve contributors at this time
236 lines (168 sloc) 8.83 KB
ispost layout title date published categories description ogimg googleimg twitterimg
The Template Tag: A Refresher
2015-11-05 03:00:00 -0800
webcomponents, template, polyfills
The only remaining browser has begun to implement the template tag. With full cross-browser support in the near future, it's time for a template tag refresher.

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:

  1. Hide the DOM off screen {% highlight html %}
{% endhighlight %}
  1. Abusing the <script> tag
{% highlight html %} <script id="simple-template" type="text/x-handlebars-template"> // My template's contents </script> {% endhighlight %}

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:

{% highlight html %} <style> span { color: purple; } </style>

<img src="" />
<span>Hello World!</span>

    function boom(){
{% endhighlight %}

###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.


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:

{% highlight javascript %} function addSimple(){ // Grab our template var t = document.querySelector('template#simple').content;

// Optional -- Modify template

// Clone and add
var clone = document.importNode(t, true);

} {% endhighlight %}

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

<iframe src=""></iframe>

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:

{% highlight html %}

<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"/>
Name Age Gender
Chester Examplefield 92 Female
1 2 3
{% endhighlight %}

Please Note:

  • Our template is inside our table
  • The template's row is not visible on the screen

{% highlight javascript %} // 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

} {% endhighlight %}

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

<iframe style="min-height: 300px" src=""></iframe>

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.


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:

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:



Questions from this reddit thread and comments below will eventually be aggregated here