Light It Up

Creating web components with lit-element.

Tagged with: programming, web

Published on and last updated on

My team and I at work are currently working on a website that is built in a very classic way with a content management system in the backend that renders pages directly on the server. There is not a lot of action going on in the user interface as it mostly displays text and image content. But one or two of our tasks required us to implement some dynamic elements for the site. Dynamic elements in this context mean elements on the page that instantly react to user input. For example, a select box which filters a list of items when a user selects a value. After some consideration, we decided to build custom Web Components for those elements. Web Components describe a collection of browser technologies that make it possible to define so-called custom elements. A custom element can be used like any other HTML element (e.g. p, a, input,…).

Although it is possible to build Web Components only with the APIs provided by browsers our choice was it to use the LitElement library as it provides a declarative way to define Web Components paired with excellent TypeScript support. To make it easier to build Web Components the library provides some decorators, lifecycle events, templating functions, and styling techniques.

To demonstrate some functionalities of the library in this article I decided to write a small component which is called light-it-up. It shows a pulsating round light in a box. It has the properties boxColor and lightColor which control which colors are used. Below is a code block that shows how the component is used in this article and the rendered component itself.

<light-it-up boxColor="#03071e" lightColor="#dc2f02"> </light-it-up>
In this div an example Web Component is rendered which shows a pulsating circular light.

Now to the fun part. The code of the whole component:

@customElement("light-it-up")
export class LightItUp extends LitElement {
  @property({ type: String }) public boxColor = "#000";
  @property({ type: String }) public lightColor = "#3F88C5";

  public static get styles(): CSSResult {
    return css`
      .box {
        // ...
      }
      .light {
        // ...
      }
    `;
  }

  // Implement `render` to define a template for your element.
  protected render(): TemplateResult | "" {
    return html`<div
      class="box"
      style="${styleMap({ backgroundColor: this.boxColor })}"
    >
      <div
        class="light"
        style="${styleMap({ backgroundColor: this.lightColor })}"
      ></div>
    </div>`;
  }
}

By adding @customElement("light-it-up") to the class it is registered as a custom element with the name light-it-up. The @property decorators make it possible to bind values from attributes to the members boxColor and lightColor. Another benefit that @property provides is the re-rendering of the component when their values change. The static get styles() getter returns a tagged template string that is used as a stylesheet for the component. And finally, there is the render() method that gets called each time the component is rendered to the browser. It uses a tagged template string html`...` which gets processed by the great lit-html templating library.

This is just a simple example as to how Web Components and libraries like LitElement can be used. Of course, there are pretty complex components that can be built without the need of including a big JavaScript UI framework into your project. The complete code for the light-it-up component can be found in the following repository.