Back to all posts
DevelopmentJan 3, 2024·6 min read

Diving into Web Components (Part 1) with Stencil.js

A brief look at building Web Components with Stencil.js & TypeScript.

Diving into Web Components (Part 1) with Stencil.js

Front end developers are constantly exploring creative approaches to build scalable and maintainable UIs and apps. Amid a plethora of web frameworks and libraries to choose from, Stencil.js has surged as a promising tool for developing web components due to it's simple API and performant runtime.

In this post I am going to give Stencil.js a test run in order to assess its merits, drawbacks, and overall standing. Mind you, this is going to be a brief post and it will not cover all there is to know about Stencil. Think of it as a primer - it's just me messing around with a tool over a weekend. I've built a fun little Freelancer widget to put all my learnings to the test which you can check out below. OK, so let's dive in.

Understanding Web Components

Web Components are a set of web platform APIs that allow developers to create reusable and encapsulated custom elements in web applications. They are designed to address the challenges of building modular and maintainable web apps by providing a standardized way to create and use components across different frameworks and libraries. Web Components consist of four main specifications: Custom Elements, Shadow DOM, HTML Templates, and HTML Imports.

Custom Elements enable developers to define their own HTML elements with custom behavior and properties. This promotes code reusability and modularity by encapsulating functionality within a self-contained custom element.

Shadow DOM allows for the creation of encapsulated and isolated DOM trees, ensuring that the styling and behavior of a component do not interfere with the rest of the document.

HTML Templates provide a mechanism for declaring reusable chunks of markup that can be cloned and inserted into the DOM as needed.

Web Components offer a powerful solution for building modular and maintainable web applications, fostering a component-based development approach. They can be utilized independently or integrated seamlessly with various web frameworks, providing developers with the flexibility to choose the best tools for their specific needs.

Understanding Stencil.js

Simply put, Stencil.js is a library for building web components and Progressive Web Apps (PWAs). Unlike conventional frameworks, it doesn't dictate specific structures. Instead, it compiles your code into standard JavaScript and web components, empowering developers to maintain familiarity with the ecosystem while leveraging the potential of modern web standards.

Stencil uses JSX / TSX to render components with heavy use of Decorators (if using TS). Here is a snippet of code from my Freelancer Widget project:

import { Component, Prop, h } from "@stencil/core";

@Component({
  tag: "minimal-profile",
  styleUrl: "minimal-profile.scss",
  shadow: true,
})
export class FreelancerScore {
  @Prop() user;
  @Prop() rating;
  @Prop({ mutable: true }) bgColor: string = "#345589";

  render() {
    const cardBg = `.card::after{ background: ${this.bgColor}; }`;

    return (
      <article class="content">
        <a
          target="_blank"
          href={`https://www.freelancer.com/u/${this.user.username}`}
        >
          <style>{cardBg}</style>
          <div class="card">
            <div class="profile-card">
              <img class="profile-card__img" src={this.user.avatar_cdn} />
              <div class="profile-card__info">
                <div class="flex">
                  <h1 class="profile-card__username">
                    {this.user.public_name}
                  </h1>
                  <star-rating rating={this.rating} />
                </div>
                <h3 class="profile-card__tagline">{this.user.tagline}</h3>
              </div>
            </div>
          </div>
        </a>
      </article>
    );
  }
}

As you can see it looks very much like React and Vue, just with Decorators to define props and other attributes. You can read more about Stencil components in the docs.

The Pros

  1. Efficiency: Stencil.js uses lazy-loading to only load components when they are needed, leading to a considerable performance boost. This vastly reduces initial load times, making apps built with Stencil.js remarkably fast.

  2. Stencil.js CLI: Stencil's CLI is included in the compiler, and can be invoked with the stencil command. With the command stencil generate you can build a new component complete with css module files, unit test and e2e test files. I love this.

  3. Future-proof: Capitalizing upon the standardized features of Web Components, Stencil.js secures your investment from the volatile evolution of JavaScript ecosystem. Even if you decide to shift to another framework or the framework you are using becomes obsolete, Stencil.js-compiled components will continue to work.

  4. Support for Service Workers: Stencil comes with robust support for service workers as it is built on top of Workbox, an open source Service Worker library by the team at Google Chrome.

After playing with Stencil.js I have to say, it is refreshingly simple to learn and use. It's very similar to React in the way that you must return a render() function to your Class component, along with JSX to interpolate your data.

While it is preferred to write your component code as a Class component, there's no headaches around binding this and calling a constructor to initiate state. I also love the fact that you can simply write class instead of className for your styles.

To sum up the pro's: Everything just works. It's fast, it's simple and it's future friendly.

The Cons

  1. Limited Ecosystem and Community Support: Compared to more established frameworks, Stencil.js has a smaller community and a more limited ecosystem of pre-built components.

  2. Functional Component Limitations: Stencil.js primarily utilizes Class components for building web components. Functional components lack lifecycle methods and local state.

My experience building a widget using Stencil.js

Crafting a Widget UI with Freelancer API

To familiarise myself with Stencil I decided to build a simple Freelancer card component. The primary goal was to fetch user data from freelancer.com and present it in a visually appealing UI card component.

I designed two distinct styles for the widget. The first, a minimalistic horizontal card displaying a profile avatar image, along with some basic data about the user. The second design is a vertical card that includes more data around the user's rating, their hourly rate, location and online status. The card gracefully flips around 180 degrees, revealing a detailed description of the user on its back.

Here's how my widgets turned out:

You can find the published widget on npm. The web component code to embed is dead-simple:

<!-- Add npm script to your web page -->
<script
  type="module"
  src="https://unpkg.com/freelancer-web-app@0.0.11/dist/freelancerwebapp/freelancerwebapp.esm.js"
></script>

<!-- Detailed card component -->
<freelancer-score
  bgColor="#7FDBFF"
  type="card"
  username="HawkGeek"
></freelancer-score>

<!-- Minimal card component -->
<freelancer-score
  bgColor="#345589"
  type="minimal"
  username="HawkGeek"
></freelancer-score>

The Verdict

I really like Stencil and I believe it holds a lot of promise. Its focus on modern web standards and interoperability makes it a strong contender among other libraries and frameworks.

If you're a developer who is eager to utilize the latest web standards and if you value efficiency and portability, Stencil.js is worth considering. Write your component code once, and port it everywhere knowing that it will "just work".

Thanks for reading! If you found this helpful, consider getting in touch or subscribing to my newsletter.

Where I Write

I write in three places: rock climbing adventures, Vedic astrology insights, and web development thoughts. Explore my writing across these platforms.