Let’s LEGO the web: Creating a custom web component with JavaScript

CBorruel
REWRITE TECH by diconium
6 min readNov 27, 2023

When building a website or web application, often we need to reuse certain elements or functionality across different pages. For example, a counter that increments or decrements a number. Instead of rewriting the code for the counter each time you need it, you can create a custom web component.

A web component is like a building block that encapsulates its own HTML, CSS, and JavaScript. It’s a self-contained element that can easily be reused throughout the website. Basically we can create our own LEGO™ blocks and reuse them as needed. By creating a custom web component for the counter, we can easily add it to any page by simply including the component’s tag in the HTML.

When creating custom web components, you’re basically making reusable building blocks for your website. These blocks have their own special features and can be easily used in different parts of your site. They make your code simpler to manage and update, and they work well across different web browsers. Custom web components give you the freedom to choose the tools you like, and they ensure that your website looks and behaves consistently for everyone who visits it.

By creating custom web components, you’re essentially creating your own unique set of LEGO™ blocks tailored to your website’s needs. Picture it like assembling a bunch of colorful bricks, playing mix-and-match, and whipping together cool web apps — just like creating awesome LEGO™ structures with different blocks.

Web Components are a set of technologies that allow the creation of customisable elements, encapsulated outside the application, which can be reused in any JavaScript library or framework that works with HTML. These elements can be widgets, buttons or any kind of function and UI that makes sense to reuse.

The most used technologies are Custom Elements; Shadow DOM; HTML Templates; ES Modules.

Some advantages of using Web Components: Reuse; Encapsulation; Productivity.

The above was shamelessly copy/pasted from this great article written by Miguel Henriques on expand-it

In this tutorial we will go step by step on how to create a custom counter web component.

Let’s get deep down into it!

Tom is down to it!

We’ve got our HTML, and we’ve crafted a component called “a-custom-made-component” nestled between tags. Granted, naming isn’t my strong suit, nor is it the focus here. Nevertheless, at this point, our live server output will merely display the text enclosed within those tags.

Code Snippet
Ouput

Ok, now let’s get to the cool part, and start creating our own counter in custom-component.js

To kick things off, we’ll import the necessary tools for crafting web components. Think of it like needing clay for ceramics, cement for bricks, or plastic for blocks — similarly, in our scenario, we’ll utilize the Lit library.

Crafting web components

Lit is a lightweight library that simplifies building web components by providing convenient functions and a declarative syntax. There are alternative options for creating web components which include Stencil, Angular, Vue.js, and ReactJs. Lit has great tutorials in case you want to dig deeper and learn more about it

So first we will import litElementand html from our Lit library.

import {LitElement, html} from "https://cdn.skypack.dev/lit";

When we import LitElement and html from "https://cdn.skypack.dev/lit", we are using the Skypack CDN to quickly access the necessary tools provided by the Lit library. Skypack is a service that allows us to import JavaScript modules directly into our code, without the need to install and manage dependencies locally.

By importing LitElement and html from Skypack, we can quickly access and use the essential tools provided by the Lit library without the need for manual setup or configuration.

LitElement is the base class for creating web components with Lit, handling component rendering, properties, and handling events.

The html function simplifies writing HTML templates in a more expressive way using JavaScript template literals.
JavaScript template literalsare a way to write strings in a more flexible and dynamic manner. They allow to embed expressions within backticks (`) and use placeholders (${expression}) to include the value of the expression within the string:

const name = 'Isaac';
const lastName = 'Asimov'
const profession = 'writer';
const message = `Hello, my name is ${name} ${lastName} and I am ${profession}.`;

console.log(message); // Hello, my name is Isaac Asimov and I am writer.

Using Skypack’s import, you avoid the hassle of local dependency management and can jump straight into creating web components. LitElement and html from Skypack empower you to build custom web components efficiently and effectively by leveraging the capabilities of the Lit library.

Actual picture of a developer creating web components

The Shadow DOM is like a private space for web components. It keeps their internal stuff separate from the rest of the webpage, so they don’t mess up other things or get messed up themselves. This separation also helps improve performance because the component’s styles and functions are contained, making it more efficient and faster to load. It’s a way of keeping each component’s details neatly organized, not mixed up with everything else on the page, and boosting how quickly the webpage runs.

In order for our component to inherit the functionalities from the LitElement we will create and export a new class called CustomCounter:

export default class CustomCounter extends LitElement{}

Inside we will model this LEGO™ brick counter of ours.

So we will need the counter to start with a 0. This is a property to keep track of the counter state. We will also need two buttons: one to increment, and another to decrement. Last but not least, we will need to render it all on our page.

This property will be used to keep track of the count value:

static properties = {
count: { type: Number },
};

The constructor() method is a special method that gets called when an instance of the CustomCounter class is created.

The super() function is used to call the constructor of the parent class, LitElement. By doing this, we ensure that any essential setup defined in the LitElement class is executed before we perform our own initialization. It allows us to inherit and leverage the functionality provided by LitElement and set a solid foundation for our custom component.

Then, we initialize the count property with a value of 0, indicating that the initial count is zero:

    constructor() {
super();
this.count = 0;
}

The increment() and decrement() methods are defined to increase or decreased the value of count by 1 whenever they are called.

   increment(){
this.count++;
}
decrement(){
this.count--;
}

The render() method is overridden to define the HTML template for our component. It uses the html template literal function mentioned above from Lit to create a dynamic template.

 render() {
return html `
<button @click="${this.decrement}">-</button>
${this.count}
<button @click="${this.increment}">+</button>
`
}

Finally, the customElements.define("a-custom-made-component", CustomCounter) line registers our component with the name "a-custom-made-component" (the one we used in our HTML). This allows us to use our component as an HTML element on the web page.

customElements.define("a-custom-made-component", CustomCounter) 

Overall, we should have a JS file that looks like this:

import {LitElement, html} from "https://cdn.skypack.dev/lit";

export default class CustomCounter extends LitElement{
static properties = {
count : {}
}
constructor() {
super();
this.count = 0;
}
increment(){
this.count++;
}
decrement(){
this.count--;
}
render() {
return html `<button @click="${this.decrement}">-</button>
${this.count}
<button @click="${this.increment}">+</button>`
}
}

customElements.define("a-custom-made-component", CustomCounter)

And that’s it! We have created our own small, reusable counter component!

This is our first small “LEGO™” brick, but as even the most complex of websites start with a hello world, a great site can also start with a small counter. Don’t fall down for the simplicity of it all, as web-components are a great -and fun- tool!

Let that sink in! See you!

--

--