Basic Web Components

What are Web Components?

Web components consist of a set of web platform APIs which allow the creation of new types of HTML elements. They have encapsulated style and behaviour and this makes them perfect for reuse across different applications.

There are four specifications which can be used to create web components:

  • Custom Elements – allow the creation of custom HTML tags
  • Shadow DOM – allow styles and scripts to be scoped to encapsulated DOM trees
  • HTML Template – allow resusable document fragments to be defined
  • HTML Imports – allow HTML files to include other HTML files

All of these can be used individually but when combined they work as a complete solution for creating and packaging web components.

Custom Elements

To create a custom element we must declare a class which extends HTMLElement. We then define the tag name associated with this type of element using CustomElementRegistry.define().

Here is an extremely simple custom element which simply has some predefined text.

class MyCustomElem extends HTMLElement {
  constructor() {
    super();
    this.textContent = 'I am an awesome custom element';
  }
}

window.customElements.define('my-custom-elem', MyCustomElem);
<my-custom-elem></my-custom-elem>

Custom elements benefit from a number of lifecycle callbacks which allow you to control the behaviour of your elements.

Shadow DOM

A shadow DOM allows an element to have its own private DOM, protecting it from the parent document and allowing it to have its own scripting and styling.

A good way to imagine this is to consider the video element. It has a number of buttons with their own style and behaviour which are not affected by the outside document. Shadow DOM allows us to create our own elements that have their own predefined structure, style and behaviour.

A shadow DOM can be created by using Element.attachShadow(). Any element can have a shadow DOM attached – both native and custom elements.

<div id="my-host"></div>
const host = document.getElementById('my-host');
const shadowRoot = host.attachShadow({mode: 'closed'});
shadowRoot.innerHTML = '<h1>I am in a shadow DOM!</h1>';
shadowRoot.innerHTML += '<style>h1 {color: green;}</style>'

HTML Templates

HTML templates allow you to define markup templates that are not initially rendered to the page when parsed but can be instantiated and rendered multiple times later.

<template id="tmpl">
  <div>Templates are cool</div>
  <p>They allow you to define reusable document fragments</p>
</template>
const templ = document.getElementById('tmpl');

for (let i = 0; i < 3; ++i) {
  const clone = document.importNode(tmpl.content, true);
  document.body.appendChild(clone);
}

Templates work well with the Shadow DOM as they allow you to cleanly define the content for your shadow root without the need to perform lots of string concatenation on innerHTML, which can get very messy very quickly. A style element can be included in the template to provide styles for the shadow DOM.

HTML Imports

HTML imports can be used as a way to include a web component in a project. They allow you to include an HTML file which packages all of the code needed for the web component.

<link rel="import" href="my-component.html">

Conclusion

Web components maximise code reuse and reduce repeated work – a major win for developers! I really like that due to their encapsulation they can be easily shared between developers and used across different applications.