I have been following the new trend of web components with excitement. These web components make it possible to create your own dom like elements. This opens up a whole new world of customization and reuse of these components. First, let me explain why then we will start creating a web component using Stencil.
Let’s say you work for a company that uses a strict style in its web applications. These style elements need to be defined somewhere. Of course, we can use CSS stylesheets for this with a well-defined style. But in my experience CSS stylesheets start to be overwhelming fast with all sorts of classes. Besides, maybe you want to add some sort of logic to a specific component. With web components adding logic is possible and all components are separated in their own files (although separating the components is possible to do with CSS).
Web components can be used with any framework or can even be used with plain HTML, JS, and CSS. This way all the components that you create today will survive the next framework.
Let’s look from the perspective of a new developer that needs to implement a button in the style that the company uses in its apps. He wants the button to be outlined, use the color primary and want all the text in the button to be uppercase.
With CSS Stylesheets this would look something like this:
And with web components, it will look something like this:
Of course, which one you prefer is subject to personal opinion. I prefer the second syntax.
In this case, fill decides how the button will look with the default behavior being, all filled in. Uppercase is a boolean that decides if the button is all uppercase or not. With this kind of syntax, it seems clearer that fill and uppercase are properties of the button. This syntax also helps in error prevention. This way it is not possible to give fill outlined and clear, which would not work as an outlined button cannot be clear. With CSS you can easily put outlined and clear together and it would not seem like there is something wrong.
Enough explaining more building. We are going to create this fictional company button. Let’s start by encapsulation a normal button in a web component.
If you have ever used React this file will look pretty familiar to you. Lot’s of concepts of Stencil use React concepts. In fact, the TSX or JSX embeddable XML-like syntax is also used by React.
Probably the first thing that you notice is the component decorator at the top of the web component. This decorator is used for configuration of the web component. We defined the tag, the stylesheet URL and if this component needs to use the shadow dom (I recommend reading this blog post from the ionic team about the shadow dom).
After the component decorator, we find the component class within it a render method. This render method will be what is rendered to the end user (hence the name render). In the render method, we see a slot element. This slot method would be everything that is encapsulated in the company-button tag. In the case of
<company-button> I’m a button </company-button> this would be “ I’m a button ”.
Styling the button
The default button is pretty bland right now. In order to use the style of the company, we need to style the look of this button. We do this by using the stylesheet defined in the component decorator (we could do the styling directly in the TSX file but I like to separate my CSS from this file). The CSS file looks like the following.
Because we are using the shadow dom we do not have to be concerned that styling the button tag directly will change any other button on the web page.
Earlier we defined that the developer wanted the button to be uppercase. So now we are going to add an uppercase property that defines if the button should be uppercased.
First, we import the prop decorator from the stencil core. With this decorator, we define the uppercase property of type boolean and we default this property to be false. With this property, we change the textTransform of the button to be uppercase when true and to initial if false.
Now we can define
<company-button uppercase>I’m a button</company-button> in the HTML and the text inside the button will be uppercased.
Now let’s create the fill property of the component. This fill property will be one of these three things: default, outlined or clear. So because we are using typescript we can create a type that helps us during the development of this component.
We can see the three stages that we defined earlier. With this made we can create a fill prop in the component. The whole file looks like this.
We see the Fill type that we defined together with a fill property that defaults to ‘default’ (of course). This fill prop is not doing anything at the moment but we will create that code soon. There is still a problem with this code, the type check is only useful for us in development when compiled the user can pass any string to the fill property. We are gonna solve this.
So, first of all, we separated the fill type to a separate file. In this file, we add an array with all valid strings that can be passed to fill. We use this array in the validateFill function in the web component. When the string passed to the fill attribute is not in this array we throw an error. This way the user using the web component will know that what they try to do does not work.
Now we are going to do something with this type and actually change the styling of the element based on the fill property.
We just change the render method of the component to add the fill value as a class to the button. In the CSS we add the clear and outlined class and this styling will be used when those fill types are chosen.
The syntax of Stencil is very similar to React and easy to pick up for most front-end developers. It is an easy way to create components that can be used in all major frameworks and can even be used in frameworks that do not exist yet. It gives more functionality than just CSS frameworks and is, in my opinion, the way to create components that will survive the next frameworks.
Check out Stencil here