Building a web-component library with StencilJS

Why a web-component library?

Adrian Rivers
6 min readMar 21, 2019

Recently at Spring Media we have been investigating whether web-components might be the answer to a very tricky riddle many organisations have yearned to solve: can one organisation develop and use a library of reusable components?

This is an especially hard riddle to solve at Spring Media because we oversee the online presence of several of our parent company’s news media publications, each publication is looked after by its own dedicated team, to further complicate the issue, each one of our teams uses their own specific tech stack to suit their own niche needs.

This is where web-components could become quite useful for us since they are now natively supported by all the major browsers, we could in theory create a library of reusable web-components which could then be slotted into any one of our organisation’s existing projects!

With all of this in mind we began investigating a very promising newcomer on the web-components scene called StencilJS. To learn what StencilJS essentially is we can take a quote directly from their website:

“StencilJS combines the best concepts of the most popular frontend frameworks and generates 100% standards-based Web Components that run in any modern browser.”

StencilJS sports several out of the box features which are very important to us as developers, namely TypeScript support and integrated unit testing. StencilJS also allows for the injection of global CSS or SCSS (with an official module) variables, this feature could be an integral part of the solution to our component library riddle, with global CSS variables it should be easy to change the appearance of all the components within the library at once from within one file.

Ok, how did you do it?

In order to test the feasibility of a web-component library we created a small test library with StencilJS, the test library was published to NPM as a module and then tested in two demo apps, one created with React and the other with Vue.

Setting up the project was easy, to start a StencilJS project all you need to do is open up a new terminal window and type:

And then choose the ‘component’ option:

As mentioned previously, StencilJS will scaffold your project for you and also provide you with a simple starter component:

Here is the simplest component we created, it takes a string as a prop and it also renders it’s children as a heading, note that the component’s children are inserted into the DOM with the special web-component slot element:

Here is the React like part of our most complex marquee component, here we use StencilJS’s Prop and State decorators as well as a lifecycle method to fire off some methods after the component has been loaded:

The marquee component was adapted from an existing Preact component:

Adapting the Preact marquee’s render function part to work in our StencilJS component was especially easy because StencilJS also uses JSX to render data:

The marquee component’s children need to be dynamically rendered; the component is meant to duplicate enough of its children to fill the width of the screen. We did this by using StencilJS’s Element decorator to gain access to the root element and subsequently the root Element’s children from within the componentWillLoad() lifecycle method which fires before the component is attached to the DOM.

We opted to use Sass for our component library, implementing Sass within StencilJS is easy, to do this you simply have to install the official sass package and then include it in the stencil.config.js file. We used the Sass plugin to inject our global variables:

Our variables.scss file contains a few variables which can then be referenced throughout the whole project:

How did it work out?

Once our component library had been built and published we set up two barebones apps, one with React and the other with Vue. Our web-component library slotted into both apps easily, to use StencilJS components within an existing React or Vue app you will need to consult the StencilJS documentation on how to include them, each framework requires a different inclusion method.

We did run into a slight issue when incorporating our component library into the React app, as mentioned previously we love TypeScript and cannot do without it so naturally we chose to scaffold our test apps with TypeScript. While we had no TypeScript issues with the Vue app we did come across some type errors which stopped the React app from compiling. StencilJS is meant to automatically generate and include custom types for your web-components but something went wrong with these generated types in the React app, there is still an open issue on Github dealing with this problem which is where we also found our workaround: adding a custom type file to fix the type error.

Here’s how a web-component looks within a React project (they look almost identical within a Vue project), note that web-component Props need to be written in kebab-case:

On further analysis with the webpack-bundle-analyzer we found that the total bundle size of our component library when used in our React and Vue apps was quite small, 10.92 KB gzipped in total.

What’s the takeaway?

The web-components we generated with StencilJS performed flawlessly when tested in our Vue and React apps. Using web-components within a React project does present a few gotchas though, for instance, React isn’t natively friendly when it comes to interacting with the DOM of web-components (workaround), also, passing rich data such as objects and arrays into web-components will cause React to throw an error and fail.

In short, StencilJS provides everything that you would need to build performant and reactive web-components as well as a sound developer experience thanks to its ease of use, TypeScript support and integrated unit testing. It is still too early to say whether or not you should choose StencilJS to build something serious right now, web-components are only just starting to become part of mainstream web-development so expect to see many more web-component compilers and tools gaining popularity in the future.

Source code

Here you can find a GitHub repository containing the StencilJS test component library as well as the React and Vue apps.

--

--