Categories
Web Components

Creating Web Components — Templates and Slots

Spread the love

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.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *