Building Web Components with Stencil

Muhammad Ahsan Ayaz
6 min readMar 10, 2018

--

Over the past few years, web development standards have evolved so much that many of us have had a hard time catching up. Even now, there’s a new javascript framework being created somewhere in the world that’ll go live in the next few months. Yet keeping up to date is crucial in the software industry and lagging behind is not an option.

As web standards have evolved, many new APIs, features, frameworks and tools have been introduced. Be it ES6, TypeScript, Webpack or libraries like Polymer, Stencil, etc. With evolving standards, one of the prominent targets of web and hybrid-mobile frameworks is to use Web Components.

What is Stencil?

Stencil is an open-source compiler that generates standards-compliant web components. Team Ionic announced Stencil during the Polymer Summit 2017. Stencil’s approach to web components specifically is using Custom Elements. The amazing thing about Stencil is that it works along with the best tools out there for developing amazing apps that can be shipped to production without much hassle. Stencil compiles components into pure web components which can be used in other frameworks like Preact, React, and even with no framework at all.

If you are familiar with React or Angular, you might find yourself at ease while developing apps with Stencil compared to those who are new to JSX and TypeScript.

Why use Stencil?

We can build web components using vanilla JS of course. But Stencil provides some syntactic sugar with TSX (JSX with TypeScript) that makes it a lot easier to build web components with cleaner, reduced code. Stencil’s core API can be used to create components, manage state with the component lifecycle methods, and inputs and outputs to pass attributes into components and emit events from the component respectively.

Here is what a stencil component looks like:

Let’s discuss the elements from the core API used in the above component:

  1. tag in the @Component decorator defines the element tag to use this component in HTML.
  2. styleUrl points to the styles (file) of the component.
  3. @Component decorator wraps the class around and registers as a component for Stencil.
  4. @Prop decorator is used for handling input (attributes data) for the component
  5. @Event decorator is used to create event emitters to emit events outside from the component.

Building Web Components with Stencil

We are going to build a stop-watch-box component using Stencil. We will use the stencil-component-starter by the Ionic team to get started. This is a great way to start building web components with Stencil since it provides the tooling and configuration out of the box.

Clone the starter app from the repository:

git clone https://github.com/ionic-team/stencil-component-starter.git stop-watch

Navigate to the folder and install the dependencies:

cd stop-watch
npm install

Remove the repository origin as you’re going to push your code into your own git repository:

git remote rm origin

Run the dev server:

npm start

This should bring up the server at http://localhost:3333/

Creating the StopWatch Component

First, we will create a stop-watch component. Create a folder inside src/components named stop-watch. Create the tsx (TypeScript) and css files for the component. The folder structure should look like this:

stop-watch component

The code below represents the StopWatch component and goes inside the stop-watch.tsx file:

The below styles for the component go inside stop-watch.css:

We have created some markup for the watch component that will display milliseconds, seconds, minutes, and hours. We have used @Prop for the variables so we will be passing these from our container/parent component. Let’s create the parent component now.

Creating the StopWatchBox Component

This component will contain the logic for starting, stopping and resetting the stop watch. For this, we will have a button for each action. To create the component, create a folder named stop-watch-box in the components folder as we did earlier for the stop-watch component. Create the tsx and css files and paste the code snippets from the files below:

Notice that we are using @State for making sure that our updated variables get rendered. The difference between @State and @Prop is that the view is not re-rendered if something changes in a @Prop. But if any of the @State models change, the view is rendered again.

While the code (tsx) might seem self-explanatory, there are two important things to note:

  1. We’re passing the state properties to the stop-watch component as:
<stop-watch hours={this.hours} minutes={this.minutes} seconds={this.seconds} milliseconds={this.milliseconds}></stop-watch>

2. We have imported WatchService in our component file, so create the watch service in the src/services folder. Now the folder structure should look like this:

The code below for the WatchService goes inside watch-service.ts:

To see it working, open the index.html file and add the below script tag inside the head tag:

<script src="/build/stopwatchbox.js"></script>

Next, use the component inside the body tag as below:

<my-component first="Stencil" last="'Don't call me a framework' JS"></my-component>
<!-- using the stop watch box component -->
<stop-watch-box></stop-watch-box>

The stop watch box should be working as follows:

You may notice that there are some errors on the console saying GET http://localhost:3333/build/stopwatchbox.js 404 (Not Found).

By default, the component starter targets the mycomponent.js file since it uses my-component. We need to use the stop-watch-box component and target stopwatchbox.js. To do that, remove the my-component folder and its file and set the stop-watch component as the main component for the build. Follow the steps below:

  1. Open stencil.config.js and replace mycomponent with stopwatchbox.
  2. Open package.json and replace all instances of mycomponent.js with stopwatchbox.js.
  3. Remove the script tag with src="/build/mycomponent.js" from the index.html in the srcfolder.
  4. Change the name property in package.json to stop-watch-box.
  5. Remove the usage of my-component from the index.html.
  6. Stop and restart the dev server. The errors should be gone now.

Distributing the Component

To distribute the component, We are going to publish this on npm. If you’re writing your own components, you can publish them on npm as well. To do that, follow the steps below:

  1. Build the component for production by running npm run build from the project root.
  2. Once the build is done, we need to publish it. Make sure the name property of the package represents your component’s name. In my case, it is stop-watch-box.
  3. Follow the guidelines from npm docs to create a user if you don’t have it already.
  4. Publish the package by running npm publish --access=public

Viola! We have our web component published and we can now use it in any framework or with no framework at all. And this is not the end. We could still add features to it like adding laps and perhaps changing the clock’s background and text colors after each lap. The possibilities are limitless! Do try Stencil to build your own web components and paste the demo links in the comments. We can’t wait to see what you build!

What’s next?

Building a web component was a breeze for me using Stencil and I could get it completed and published within a few hours. Check out the code from this repository, and then view the demo here. It also contains the hover effect implementation.

Make sure to check out Stencil‘s docs for building more complex web components. The docs have information on state management, events, methods, forms and almost everything that should get you started.

While Stencil provides a great way to build web components, there are other choices as well. For example, StakeJS, Polymer, and other libraries as well as frameworks like Angular and Vue are also on the way to allow developers to build Web Components.

P.S. Thanks for reading this far! If you found value in this, I’d really appreciate it if you recommend this post (by clicking the 👏 button) so other people can see it!

--

--

Muhammad Ahsan Ayaz

Educator | Angular GDE | Speaker | Author of Angular Cookbook | Left medium and now on https://dev.to/codewithahsan