Now, we have a nice reusable tooltip element, but we also have quite a bit of code along with our style tag that is made up entirely of a templated string. What would be best is if we could have this semantic markup put somewhere else and have the execution logic in our web component as it is now. This is where templates come into play. The <template> element will not be displayed on the page, but we can still grab it quite easily by giving it an ID. So, one way of refactoring our current code would be to do the following:
<template id="tooltip">
<style>
/* left out */
</style>
<span class="wrapper hidden" x="0" y="0" type="default" show="false">
<span id="icon">ક</span>
<span id="main">This is some default text</span>
</span>
</template>
And our JavaScript class constructor should now look like this:
constructor() {
super();
this.type = this.getAttribute('type');
this.typeMap = // same as before
const template = document.querySelector('#tooltip').content;
this.shadow = this.attachShadow({mode : 'open'});
this.shadow.appendChild(template.cloneNode(true));
}
That is much easier to read and much easier to reason about. We now grab our template and get its content. We create a shadow object and append our template. We need to make sure to clone our template nodes otherwise we will share the same reference between all of the elements that we decide to create! One thing you will notice is that we cannot now control the text through an attribute. While it was interesting to see this behavior, we really want to leave that information up to the creator of our tooltip. We can do this through the <slot> element.
A slot gives us an area where we can put HTML in place of that location. We can utilize this to allow users of the tooltip to put in the markup they want for that slot. We could give them a template that looks like the following:
<span class="wrapper hidden" x="0" y="0" type="default" show="false">
<span id="icon">ક</span>
<span id="main"><slot name="main_text">This is default text</slot></span>
</span>
And our implementation may appear as follows:
<our-tooltip show="true" x="100" y="100" type="success">
<span slot="main_text">That was a successful operation!</span>
</our-tooltip>
As we can see, the use of the shadow DOM, along with web components and the template system in our browser, allows us to create rich elements without the need for external libraries such as Bootstrap or Foundation.