How does a browser handle a <template> tag VS a <div> tag

4.9k views Asked by At

I have been reading the documentation on the <template> tag, and I can't seem to understand how it is different from simply using a <div> that is display: none;

Documentation: template tag

<template> example

<template id="productrow">
  <tr>
    <td class="record"></td>
    <td></td>
  </tr>
</template>

VS <div> example

<div id="productrow" style="display: none">
  <tr>
    <td class="record"></td>
    <td></td>
  </tr>
</div>
  1. On a low level, how does the browser handle these 2 examples differently?
  2. Are certain JS methods or HTML attributes different or not available?

PS: I am aware of browser compatibility differences

3

There are 3 answers

3
Jordan Running On BEST ANSWER

Consider:

<template>
  <style>
    body: { background-color: black; }
  </style>
  <script>
    alert('hello');
  </script>
  <audio src="alert.wav" autoplay></audio>
</template>

And:

<div style="display: none;">
  <style>
    body: { background-color: black; }
  </style>
  <script>
    alert('hello');
  </script>
  <audio src="alert.wav" autoplay></audio>
</div>

Are these going to behave the same when the browser renders them? (Spoiler: no.)

To address your specific questions, though:

  1. On a low level, how does the browser handle these 2 examples differently?

For one, the HTML inside a <template> does not become DOM elements that are children of the <template>. It becomes children of an "inert" DocumentFragment (indirectly; this is a simplification) where they exist as nodes but do not "do" anything, as in the example above.

In addition to being "inert," the template contents have no "conformance requirements." Your <tr> example above is a good one. See what happens here:

const template = document.querySelector('template');
const div = document.querySelector('div');

console.log('template.innerHTML is', template.innerHTML);
console.log('div.innerHTML is', div.innerHTML);
<template>
  <tr>
    <td class="record"></td>
    <td></td>
  </tr>
</template>

<div style="display: none">
  <tr>
    <td class="record"></td>
    <td></td>
  </tr>
</div>

In a normal document, a <tr> can't be a child of a <div>, so the browser just removes it. In a <template>, that requirement doesn't exist. You would find the same with, say, <div style="{{myStyle}}">. In a document, the browser would throw away the style attribute because its value is invalid; in a <template> it would not. This is what makes <template> useful for, well, templating.

If you want to know more about how <template>s are rendered, I suggest reading the section about it in the HTML spec. It's not easy reading, and parts may be incomprehensible, but you stand to learn a lot.

  1. Are certain JS methods or HTML attributes different or not available?

The <template> element has the content attribute, which points to the DocumentFragment discussed above.

0
Sebastian Speitel On

Elements inside of <template> can't be found by any selector in JS, so you can't accidently find them and to extract them you have to use the content property of the HTMLTemplateElement using something like:

var clone = document.importNode(templateElement.content, true);

Also every <style>, <audio>/<video>/... or <script> is parsed on page load, but doesn't run until you clone it to into the main DOM.

0
PrivatMamtora On

I found an article that explains all the differences in detail: https://www.html5rocks.com/en/tutorials/webcomponents/template/

I realize now that the <div> example was actually, kind of a polyfill used in older browsers and has to be severely hacked to make it work as expected.

Thanks for everyone's help.