As web apps get more complex, we need some way to divide the code into manageable chunks. To do this, we can use Web Components to create reusable UI blocks that we can use in multiple places.
In this article, we’ll look at how to use templates and slots with Web Components.
Templates
We can use the template
element to add content that’s not rendered in the DOM. This lets us incorporate them into any other element by writing the following HTML:
<template>
<p>Foo</p>
</template>
Then we can write the following JavaScript to incorporate it into the page:
const template = document.querySelector('template');
const templateContent = template.content;
document.body.appendChild(templateContent);
We should see ‘Foo’ on the page when we load the page. The p
element should be showing when we inspect the code for ‘Foo’. This confirms that the markup isn’t affected by the template
element.
Using Templates with Web Components
We can also use them with Web Components. To use it, we can get the template
element in the class for the Web Component just like we do outside the Web Component.
For example, we can write:
customElements.define('foo-paragraph',
class extends HTMLElement {
constructor() {
super();
let template = document.querySelector('template');
let templateContent = template.content;
const shadowRoot = this.attachShadow({
mode: 'open'
})
.appendChild(templateContent.cloneNode(true));
}
})
In the code above, we get the template
element and the call cloneNode
on templateContent
which has template.content
as the value to get the template’s content.
Then we call cloneNode
to clone the template.content
node’s children in addition to the node itself. This is indicated by the true
argument of the cloneNode
function call.
Finally, we attached the cloned templateContent
into the shadow root of the Web Component with the attachShadow
and appendChild
methods.
We can also include styling inside a template
element, so we can reuse it as we do with the HTML markup.
For instance, we can change the template
element to:
<template>
<style>
p {
color: white;
background-color: gray;
padding: 5px;
}
</style>
<p>Foo</p>
</template>
Then we should see:
Photo by Zoë Reeve on Unsplash
Slots
To make our templates more flexible, we can add slots to them to display content as we wish instead of static content. With slots, we can pass in content between our Web Component opening and closing tags.
It has more limited support than templates. Slots can be used with Chrome 53 or later, Opera since version 40, Firefox since version 59, and not supported in Edge.
For example, we can add some slots by writing:
<template>
<slot name="foo">Default text for foo</slot>
<slot name="bar">Default text for bar</slot>
<slot name="baz">Default text for baz</slot>
</template>
Then given that we have the same code as before for defining the foo-paragraph
element in JavaScript, we can use it as follows:
<foo-paragraph>
<p slot='foo'>foo</p>
<p slot='bar'>bar</p>
<p slot='baz'>baz</p>
</foo-paragraph>
The output then will be:
foo
bar
baz
If we omit the elements inside the foo-paragraph
tags, we get the default text:
Default text for foo Default text for bar Default text for baz
In the code above, we name the slots with the name
attribute in the template
element, then in our Web Component, we fill in the slots that we defined by using the slot
attribute.
We can style them like any other template
element. To style them, we select the elements to be styled by using the selector for the elements that we’ll fill into the slots.
For example, we can write:
<template>
<style>
::slotted(p) {
padding: 5px;
background-color: black;
color: white;
}
::slotted(p[slot='foo']) {
background-color: gray;
}
</style>
<slot name="foo">Default text for foo</slot>
<slot name="bar">Default text for bar</slot>
<slot name="baz">Default text for baz</slot>
</template>
<foo-paragraph>
<p slot='foo'>foo</p>
<p slot='bar'>bar</p>
<p slot='baz'>baz</p>
</foo-paragraph>
The ::slotted
pseudo-element represents elements that has been placed into a slot inside the HTML template. Therefore, we can use it to select the slot elements that we want to style.
In the argument of ::slotted
, we can pass in the element that we want to style if they were passed into the slot. This means that only p
elements that are passed in will have styles applied to them.
::slotted(p[slot=’foo’])
means that a p
element with slot
attribute values foo
will have styling applied to it.
Then we should get the following after applying the styles:
Templates and slots let us create reusable components that we can use in Web Components. The template
element does not show up during render so we can put them anywhere and use them as we wish in any Web Component.
With slots, we have more flexibility when creating Web Components since we can create components that we can insert other elements into to fill the slots.
In any case, we can apply styles to the elements as we wish. We have the ::slotted
pseudoelement to apply styles to specific elements in slots.