Have you ever heard of web components? Maybe you have wondered how much effort is involved in creating one? Maybe you have made a web component but then wondered what is the point and have just gone back to using your favourite framework. In this blog post we will walk through the process of creating a simple web component. We will also introduce different techniques for creating web components and discuss cases where web components can be useful in modern web development.

An idea for building a web component

Browsing indiehackers.com one day, I came across an interesting interview with the creators of peakfeed.com — a social media dashboard. In the back of my mind I had wanted to start creating web components, especially now that they have more widespread support in modern web browsers. Seeing the PeakFeed widgets visualising various metrics from social media platforms gave me a good idea of something to build. In this blog post we’ll be creating a simple web component which allows us to show some statistic in the PeakFeed way.

The PeakFeed website (as it appeared on IndieHackers)

Intro to web components

Web components are a suite of technologies which when combined can allow us to create reusable components (bundles of HTML, CSS, JavaScript) for the web. Mainly, the technologies are the shadow DOM, <template> tag and custom elements. The exciting possibility of web components is that it could allow us to create component-based applications natively in the browser, with similar ease that component-based frameworks lend to us (e.g. Vue and React).

Browser compatibility

Whilst Web Components do have good browser support among modern web browsers, it’s true for many organizations that they have to support legacy browser versions to a certain degree. If you are using an up-to-date version of a chromium based browser, these examples should run out of the box. However if your version of Firefox is less than 63 (released in October 2018), you will need to go to about:config in your browser and set some of the web component flags to true (the easiest thing to do is just search for webcomponent in about:config and check that most of the relevant flags are set to true), more information available from MDN. Web components are currently not available in Edge on desktop.

Custom Element

The first thing we need to get started with web components is a custom element. This is a JavaScript definition for our component which then allows us to create elements in HTML with whatever name we want (as long as it is hyphenated). There are also several life cycle hooks for us to add all of the javascript we want associated to the custom element.

Initial boilerplate code for creating our custom component

<template> tag

The template tag is just an HTML tag in which we can write any HTML to be accessed at a later time. The HTML is not rendered on the page, but is easy for us create a DOM structure for our component. The drawback to using a template tag is that the web component code is no longer self-contained. Instead of having the definition for the re-usable web component in a single file, the person who includes the web component would have to include the template tag in each HTML page. There is an import tag which could improve the portability of web components, but it lacks browser support or even an agreement of how it should work.

Shadow DOM

The shadow DOM allows us to associate a new DOM tree to our custom element. If you are familiar with a front-end framework such as React, Vue or Angular, you’ll know that most components you create are actually built up by many DOM elements. For example, if you were creating a search component, the template may actually be composed of a form, some divs, input and label tags. There will also be CSS and the shadow DOM let’s us attach this to our component also.

Going back to our example, we can now create our custom element in the HTML page:

<social-stats></social-stats>

Lurking in the shadows, are the actual building blocks of HTML and CSS which define the tag in a way that is renderable for web browsers.

Using the shadow DOM is quite simple. We first attach a shadow DOM to our custom element. The mode can be either ‘open’ or ‘closed’. It’s far more common for the mode to be set to open as the user of the web component is then able to customise it once the component has been added to the DOM. While ‘closed’ just gives you the illusion that your component cannot be tampered with. Using the method ‘appendChild’ we can append HTML elements to our shadow DOM.

Boilerplate code to run once the component is ‘connected’ to the real DOM of our web page

Using ‘h’ as an alternative to template tags

One of the problems of using a template tags as mentioned earlier, is that it diminishes the extent to which our component can be encapsulated. An alternative to using template tags then, is to just use JavaScript to create HTML elements. It’s cumbersome to continually use createElement, appendChild, setAttribute etc. when creating elements, so instead we can create a helper function to allow us to tersely create new HTML elements. The following code is strongly inspired by the javascript library ‘hyperscript’, we can just include this function in the same file as our web component:

The ‘h’ function to create HTML elements

Back to the HTML

Let’s get back to the HTML, now is the time to define more attributes for the social-stats tag. Let’s imagine that the widget allows the user to pass in data of previous values, current values and target values. For example, they could be monitoring the number of twitter followers and want to see their growing popularity in weekly snapshots. We’ll allow the user to define the following properties for the tag: name — the name to be displayed, oldnum — the previous number, newnum — the new number, target — the target number, colour — the colour of the progress bar.

index.html — featuring custom element tags

Defining attributes for a custom element

In order to use the custom attributes defined in the HTML of our component, we need to define these in the JavaScript of our component by implementing the static method ‘observedAttributes’. We can then use this.getAttribute to get the value for any of those attributes. We’ll be using the values when building up our shadow DOM, so now we will pass the values as parameters to our (yet to be defined) function ‘getDefaultTemplate’.

Getting custom attributes from our custom element

Creating the HTML and CSS

We can use the ‘h’ helper function we created earlier to define the HTML and CSS for our components. We can also pass in some of the values from our custom attributes to these functions.

Using ‘h’ to create the HTML elements and style for the custom component

Final design

Our new Web Component in action

That’s the simple design created. It’s not a lot of code required to begin using web components and there are many ways a simple component like this could be extended: start handling events, connect to real data sources, improve the design. If you’d like to see all the code for this project, it is available here: https://github.com/dalaidunc/social-stats

The future of web components

Although Web Components were first announced in 2011 and Polymer (a library from Google for enhancing web components and providing polyfills) has been around since 2013, I would hazard a guess that their usage in products is a relatively niche slice of the wider javascript landscape. Support for native web components is still very new, with Firefox only recently supporting most of the specifications in version 63 and Microsoft providing limited or no support in Edge. In addition to this, some of the Web Component specification is yet to be formally agreed by browser vendors.

The Web Component specification, whilst powerful in its own right, seems to lack some of the elegance of React or Vue code. The ‘observedAttributes’ static method feels weird and the ‘mode’ option when attaching a shadow DOM seems redundant. Perhaps there will be more evolution in the Web Component specification. Indeed, it is likely that both the specification and developers who create Web Components will continue to borrow innovations from frameworks (see a recent example here).

I think that frameworks such as React and Vue are still going to be around for a while. Web components do nothing to help manage the state of an application, nor do they provide a virtual DOM or many of the other nice things that such component-based frameworks provide. However, there is always the case to be made that for many smaller projects, using such frameworks are overkill and can needlessly bloat websites. Having web components around as a viable option for vanilla JS is an exciting prospect and I’m sure in the next few years we will see greater usage of them.