How to Instantiate HTML Template Elements

Mommy, where do template elements come from?

Most likely, you won’t write them by hand. Instead, they’ll be generated from template literals, JSX, or something else. These generators will have to deal with template instantiation. By using template elements, these generators share the efficiency of using the built-in parser and cloning DOM sub-trees.

Why use template elements?

The efficiency of template elements comes from two things: they use the browser’s HTML parser, and instantiation uses sub-tree cloning.

How to instantiate a template element

After we have a template element, we need to instantiate it. First, we use document.importNode to get a document fragment. I haven't yet needed to separate the cloning and adoption steps, but if you're curious then look at this comment in the lit-html source. Next is to get references to the elements we care about within that fragment. I know of three general ways of doing that. Let's talk about each method and then compare them.

  1. With a descendant path, we can do a minimal traversal.
  2. For small templates, the JS overhead of using a tree-walker or the descendant path makes them slower than getElementById or querySelector. If you have more then one element, then using tree-walker, descendant path, or querySelectorAll would be better.
  3. Make templates as large as you can. Doing so reduces the JS overhead of working with the DOM. Event delegation is one technique you could use to do this.
  4. Lastly, why isn’t there a constant time method? This is the API that we’re missing and should be created as part of defining template instantiation. The browser has already touched all these nodes once when it parsed them and again when it cloned them from the template. What we need is a way of telling the browser at parse time what nodes we will want wrappers for.

Reduce, Reuse, Recycle

Once your instance is no longer needed, you remove it from the DOM. You could let it be garbage collected, or you could preserve it in a pool. Pooling is an advanced topic, and I’m not qualified to talk about it anyway (what is a high water-mark?).

  1. All changes you make to the template instance need to be reversible. That is, you have to be able to clean the instance so that it’s ready for reuse.
  2. You need to be able to retrieve the instance from the DOM. This means putting the nodes back into a document fragment to be returned to the pool.

Conclusion

So how do you instantiate a template element? If it’s small and you only need a few references, then using querySelector or getElementById is fine. If your template is large, then prefer querySelectorAll, tree-walker, or descendant path. Consider pooling the instance to save the cost of cloning and finding references. And if you’re part of a standardizing body then I’d love to talk about a constant-time element access API.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Evan Brass

Evan Brass

I write a lot of ECMAScript… enough to have plenty of mistakes to learn from.