29
Apr

Web Components in 2020

Nowadays it feels like everyone is crazy about code reusability. The developer’s ability to create reusable components helps them establish some kind of common pattern or convention in their application.

We even see open source tools like Bit take reusability to the next level, so you can develop, share and sync components at scale between your apps.

After all, it would be better for you as a developer if you didn’t have to build the same button component again and again in your project, with just some minor changes between each of them, right?

In my honest opinion, a truly reusable component is one that can be used anywhere and everywhere – The component built in one framework/library can be inserted into another framework/library.

But every framework/library has its own sets of rules that the developer needs to follow. And until now code reusability has been easier to follow if you are working in just a single framework/library. But there are things can Vue can do that Angular and React can’t, and vice versa.

In some of my previous posts, I showed you how Angular has provided us with Angular Elements that can be used to insert an Angular component as a custom element into React or Vue.

But this requires you to have a certain level of understanding of how Angular Elements works.

What we truly need, is something simpler that works in any latest browser and in any JavaScript library/framework.

Enter Web Components!

Web Components is a group of features that allow us to create completely reusable components. In this post, we will take a look at how web components work and how you can use them in your projects.

Web Components are really hot right now, not only because major companies like Netflix and Youtube are already using them, but also because Microsoft recently announced that Edge will soon provide native support to Custom Elements, which is one of the APIs that is used to create web components.

Web Components — What Are They?

As mentioned before, web components are a group of features that let us create reusable components. The best thing about these components is that they nothing more than HTML elements, which means you do not have to install any new framework or library to use them. All you need is pure vanilla javascript!

Web components are created using these primary APIs:

  • Custom Elements
  • Shadow DOM
  • HTML Template

Let’s take a quick look at what each of these technologies are:

Custom Elements

The Custom Elements API is what we actually use to create our custom HTML elements and attach any desired functionality to that element. It lays the foundation on which we can design and use our own elements.

Shadow DOM

This API with a cool ninja-like name of Shadow DOM helps the developer enclose things like styling and markup of the components. Through Shadow DOM, the web browser renders the elements without putting them on the main DOM tree. This is done by creating a sub-DOM tree that is attached to the main DOM tree.

HTML Template

The template is an HTML tag inside which we can write reusable chunks of code. Nothing inside the template will run, load, or render until it is activated by stamping out the template.

Web Component Lifecycle Methods

Like any other component in Vue or React, Web Components also have a few lifecycle methods. They are:

  • Constructor
  • connectedCallback
  • disconnectedCallback
  • attributeChangedCallback
  • adoptedCallback

The constructor function runs when the component is created, but has not been inserted into the DOM. Like in other frameworks and libraries, constructor is a great place to initialize the state, and we can even set event listeners, creating the Shadow DOM for the component.

When the component is inserted into the DOM, the connectedCallback function will be executed. It is similar to componentDidMount from React, and we can use to do things like fetching data from an API.

As the name probably suggests, disconnectedCallback function is called when the component is removed from the DOM. The function is most useful when we need to remove any event listeners that are connected to a component that is no longer in the DOM.

The attributeChangedCallback function is called when the component’s “observed” attributes get changed.

Getting Started – Creating our first component

To get started, all we need to do is create a new folder where you can store all the code that you are about to write. You can do this the traditional way, or you can go to a terminal are type the following command:

$ mkdir movieswc

This single command will a new folder called movieswc in your system.

Before moving forward, let me quickly explain the app that we are about to build.

The app is going to be CRUD type where the user can create a list of movies that are going to release in 2019. So the app should contain an array of movies that will be created by the user by entering the movie name and the movie’s release date.

The user will also be able to remove the movie from the list or mark it as “released” or “unreleased”.

Now back to the application. Start by creating the index.html file inside the movieswc folder and write the following code inside it.

<html>
  <head>
    <script type="module" src="movielist.js"></script>
  </head>
  <body></body>
</html>

The only thing of notice here is the script tag inside the head of the HTML file. It is pointing a file named movielist.js and we haven’t created it yet. So let’s take care of it and write the following code inside that file:

const template = document.createElement('template');
template.innerHTML = `
  <style>
    :host {
      display: block;
      text-align: center;
    }
    button {
      border: 2px solid blue;
      cursor: pointer;
      margin: 25px;
    }
    input {
      border: 2px solid black;
      margin: 5px;
    }
    ul {
      list-style: none;
      padding: 25px;
    }
  </style>
  <h1>My Movie List (2019)</h1>
  <div>
    <input id="name" type="text" placeholder="Enter movie name"/>
  </div>
  <div>
    <input id="date" type="text" placeholder="Enter release date"/>
  </div>
  <button>Add</button>

  <ul id="movies"></ul>
`;

class MovieList extends HTMLElement {
  constructor() {
    super();
    this._shadowRoot = this.attachShadow({'mode': 'open'});
    this._shadowRoot.appendChild(template.content.cloneNode(true));
    this.$movieList = this._shadowRoot.querySelector('ul');
  }
}

window.customElements.define('movie-list', MovieList);

That’s a lot of code in one sitting! Let’s take a look at what it all means.

First, we are creating a template element on the document and inserting some HTML inside of it using innerHTML on the template along with some CSS code. You will notice that we have written a selector called :host, even though we have not used it anywhere in the HTML. host is used to set the styling of the component from the inside.

After that, we are creating an HTML element called MoviesList. Inside of its constructor function, we are attaching the shadowRoot and setting its mode to open. Then, we are cloning our template into the shadowRoot. We have also created the movieList and set it to the currently empty unordered list in our app.

By doing all this, we have created an enclosed DOM tree that will not let any of our styles to leak or get overwritten.

There is one last thing in the above code, which is probably the most important of all of the code that we have written till now. This last line of code registers the MovieList element to the CustomElementRegistry. CustomElementRegistry is used here to define the element and we pass it our desired name of the element (movie-list) along with the actual name of the element (MovieList).

Its very important to know that the name of any of our web components should contain a - in it. If you try to create an element like movielist or movieList, then it won’t work.

With all of that taken care of, we can insert the Web Component into the HTML file’s body.

<body>
  <movie-list></movie-list>
<body>

Opening the index.html file on the browser should give you something like this:

Looks good enough, but we can’t really do anything with it yet. You can click on the button or enter something in the input fields. But nothing else will happen in the browser. In order for our Web Component to communicate with the user or with other things in the application, then we need to create something called Properties.

give loveWeb Components in 2020 296

Web Components in 2020