This is the first in a series of posts about creating a web component library using Stencil.js
I've been doing frontend development professionally since 2012. During that time, I've learned JavaScript framework after JavaScript framework. I started with Backbone.js and disliked it quite a bit. I'm sure it was a great framework at the time, but I use it as a curse word to this day. I was thrilled to learn Angular.js back at the end of 2012, and shocked everyone by re-writing our complex backbone application with Angular.js in a matter of two days, with approximately 1/8th the amount of code.
That weekend kicked off a love for learning new JavaScript frameworks that has never left me. I followed closely the development of Angular, the successor to and complete re-write of Angular.js, and still use Angular heavily in my current job at Domo. React also came along and brought with it a different paradigm of not being an all inclusive "framework", but rather a view rendering library. I loved learning a whole new way of building applications, by wiring together the various pieces I needed using different libraries in addition to React. I've of course messed around with many other frameworks including but not limited to Ember.js, Vue, and Aurelia.
Component Libraries
I highly recommend the usage of component libraries. Unless you're an amazing designer as well as developer, they simplify things a great deal for most of us. In all my aforementioned experimentation with frameworks, however, I discovered a major pain point. Any time I used a new framework, the component library I used likely had it's own specific version for that new framework, or it didn't have a version for it at all. For example, I heavily use Angular Material at work and on side projects. However, whenever I work on a React app, all those components are obviously unusable in that React app because it's Angular specific. So, I find the most commonly used React alternative, Material-UI. While a great library, I now have to do a context switch as these components were built with entirely different individuals, architecture, and terminology. This is the best case scenario, however, as that is with two of the most widely used frameworks with one of the most widely used design systems.
Many companies are now open sourcing their own component libraries using their business style guide. Libraries such as Atlaskit by Atlassian, Clarity by VMWare, or Carbon by IBM. In the case of IBM specifically, they had to release one version of the library for Angular, one for React, and another for no framework with just HTML and CSS partials, similar to how Bootstrap works. This is simply not feasible or maintainable for most businesses without the resources of IBM. Instead, many pick a framework of choice and release only that library.
Enter Stencil.js
I've rarely been as excited about a technology in the last few years as I have about Stencil.js. It's not another framework; in fact it's not a framework at all. Built by the Ionic team, Stencil.js took a different approach. Instead of providing a component framework, they built a component compiler, which takes components built with modern tools and high level APIs such as TypeScript, decorators, and TSX, and compiles them down to standards-compliant web components. You don't need a framework to run these components, they're using native browser APIs to render custom elements.
The web component standard consists of various APIs that together allow you to render complex custom elements. While you could absolutely write these yourself, they are purposely designed to be low-level APIs. This is why I highly recommend Stencil, it takes the best parts from Angular and React when it comes to building components, and takes care of the rest of the complicated work for you such as dynamically polyfilling missing features and performing async rendering. All the benefits of a library like React, but using the platform itself, which allows you to use these components in any framework or no framework at all.
A Basic Stencil Component
Let's take a look at a basic Stencil component.
import { Component, h, Prop } from '@stencil/core';
@Component({
tag: 'hello-world',
styleUrl: 'hello-world.css'
})
export class HelloWorld {
@Prop() name: string;
render() {
return (
<p>
Hello {this.name}!
</p>
);
}
}
You would simply use this component in a standard HTML page like so:
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<hello-world name="John Woodruff"></hello-world>
</body>
</html>
If you're familiar at all with Angular, you'll recognize the component decorator:
@Component({
tag: 'hello-world',
styleUrl: 'hello-world.css'
})
This decorator allows you to define the HTML tag name, and a link to the stylesheet that will provide the CSS for this component.
After the component decorator, you have a plain TypeScript class. You'll notice a @Prop()
decorator on the class property name
. This defines that there is a public prop you can use on your custom element to pass in a string to the name
property.
Finally we have the standard render()
method. You return TSX (TypeScript XML) which is the markup that will be rendered in your custom element. In this case we're simply passing back a <p>
tag with a message. This message is "Hello" with the name that we passed in on the prop. If we were to change the name passed to the prop, the component would detect that and re-render accordingly.
Why Stencil?
You, a savvy reader, may be asking yourself why would I choose Stencil when I could use Polymer instead? The answer is that you're absolutely welcome to use Polymer. It's a great technology that has helped bring web components to the web at large. Personally I love building web components with Stencil much more than with Polymer, just due to the developer experience and tools used. It's a very similar experience to building components in React and Angular, two technologies I'm very familiar with.
In other reasoning, Stencil-compiled web components are highly performant, small, and incredibly easy to build and publish. You could publish a single web component, or an entire library of components. I've been using Stencil for months now in building out a component library at my job. The experience has been overwhelmingly positive for me, and we now have a library of shared components that can be consumed in the various frameworks being used throughout the company.
Next Steps
If you've made it this far and are still interested in building a component library along with me in these posts, thank you for being here! This first post had very little in the way of actual code, as I didn't want to jump into that before you had the reasoning and benefits clear in your mind. Now that we've gotten that, I'll see you in the next post!
Simply want to see the end result repo? Check it out here
Top comments (22)
I like your tutorial on Stencil, I like that you explain it properly, other sites they just show the code without explaination.
In the 'build' folder, I see many files but you only include 2 files (mountain-ui.js and maountain-ui.esm.js)
the other files are needed for the web components to work?
In the 'dist' folder, I see in the folder button, button.js and button.css. how could I use this in Angular. Do I just import the button.js and use it? Same for the tabs folder?
I see the button have class 'hydrated'. what is this used for and how do you set it up?
And could you explain how the following is working:
button.tsx
private getCssClassMap(): CssClassMap {...
I just want to use Stencil for my library development for web component.
Is there a datepicker web component anywhere?
I found a few that a person did but was not a company(2+ employee) so I'm not sure how reliable it is.
Could you write one ;-)
Thanks Donald! I appreciate your comment, I'm glad it's helpful. I'll attempt to answer you questions as best I can:
You're right, I'm only including two files in the index, but those other files are chunks that are lazy loaded on demand, so yes those are all necessary.
Integration with various frameworks is actually for the most part trivial. You can see their Framework Integration docs to know how to use the components. Specifically for Angular, you can use this page.
a. Stencil components become "hydrated" upon loading them in the DOM, and that class is added when they're ready to be used. (for example, calling the methods on the component from outside) You don't need to do anything for that to take place, that's built in.
b. That
getCssClassMap()
method is simply a little helper function I wrote to return an object with class names and whether or not to add those to the element where I'm using it. It's very simple in the button file because I'm always adding them, but it can be more complex if I have, for example, ternary statements determining whether or not to add classes. That's just a matter of preference and you're welcome to do it however you want. :)a. There is a great GitHub repository with a bunch of Stencil resouces, awesome-stenciljs, including existing component libraries. Your guess is as good as mine for how reliable it would be. ¯_(ツ)_/¯
b. Haha, maybe one day! Who knows?
Thanks a lot for your response,
I was looking at your github for easy-calendar.
I cannot see it in the browser, gives errors when build.
Is it supposed to work when I do a npm install and npm start?
github.com/johnbwoodruff/easy-cale...
Unfortunately that's a project that has languished into sadness. :( Haha. I've not touched it in nearly two years so I would imagine it definitely wouldn't work, and it wasn't near being ready anyway. I should probably archive that.
Good grief there are a bunch of things I should be archiving. 🤦♂️
I guess it should be name not-so-easy-calendar. ha ha
for item 4, getCssClassMap(), this you can do this as you are using JSX right?
the problem with stencil is it doesnt have any job market, so if you already have a job its great otherwise if you are looking to learn a tech to find a job then sadly we have top pick a framework like angular or react.
I'm not advocating learning Stencil for the purpose of obtaining a job, but rather suggesting when you build a component library, you look at Stencil as an option instead of locking in to a single framework.
you can actually choose your path with stencil either by using it's pure js approach or adopting angular/vue/react. the result will just compile to pure web component but you'll gain knowledge at the path you chose
Hi,
How to install and use bootstrap and other libraries in stencil.? I'm stuck with installing and use bootstrap in stencil! it will be more useful if you give any solution on this!!
Are you building a full app using Stencil? Or are you wanting to use Bootstrap as a base for your stencil components? Not sure I understand your need.
Sorry for an inconvenience.Yeah I have planned to create a full web app i mean a chat page not exactly but like gmail to integrate it with existing angular and vue applications.But i do not know how install and use bootstrap in stencil.Can you help me on this!?
So if I understand correctly, you're building a web component that you want to include in Angular and Vue applications, and you want to use the Bootstrap styling.
With any library that you include in other applications, I recommend defining dependencies as peerDependencies, so you require the library using your component to install both the component and Bootstrap, or use the already existing Bootstrap if they already have it installed. This way you're not bloating your small web component with the entire Bootstrap package.
I highly recommend joining the Stencil Slack as you have a large community of people there willing to help out with these kinds of issues.
Please help me .. How can I use boostrap... We are planning to develop a few pages application with stencilJs.. We require Bootstrap.. How to use it
Just wondering, when the component is compiled from typescript and published, are you able to use the component without including Stencil.js lib in your project?
Yep! Stencil is purely a compiler, the output is plain JavaScript web components. You add it to an app as simply as adding a script tag! I'm going to go over using these components in various apps and frameworks in a later post. :)
Ah that’s awesome. That’s one benefit over Polymer!
everyday I discover a new Js library or framework
Did you try Svetle? It's not as popular but I read that it's good. Would love to know your thoughts.
I haven't personally tried Svelte, but I've seen comparisons posted on Twitter before. It doesn't look to me like they turn your components into full standards-compliant web components, which is the purpose of Stencil. It appears to just turn them into javascript code. I'm not sure if it uses web component APIs such as the Shadow DOM. It appears as though they have different goals.
I just looked at Svelte, and looks similar to Vue, and I don't see a benefit of using Svelte over Vue.
Stencil (and Polymer and LitElement) work with web components, so they are not really frameworks, more like wrappers around existing web components API.