StencilJS is an open source compiler for generating web components. It is used by companies like Apple and Amazon. It was built by the team behind the Ionic Framework and it is the technology used to built the Ionic design system itself. It is small, fast and easy to learn. The best part is that you can integrate the components with all major frameworks like Angular, Vue or React. This is awesome because it allows your team to future proof your components regardless of the technology being used to render the UI.
Creating a component
Components are created with the Component
decorator. The syntax is exactly to that of an Angular component. Stencil components are rendered using the declarative syntax JSX. For those familiar with React you will find it convenient when declaring component templates. Like react components, the component class requires a render method that returns HTML
. Visit the JSX React docs to learn more about the syntax.
// button.tsx import { Component, h } from '@stencil/core'; @Component({ tag: 'my-button', styleUrls: ["./button.scss"] }) export class ButtonComponent { render() { <Host class="my-button"><slot/></Host>; } }
Inner content with Slot
Stencil components can render dynamic children using slots. Slots are similar to Angular transclusion using the <ng-content>
tag. Like Angular you can name your slots to allow users to add dynamically rendered children at specific locations. You can have many slots in a component, but only one can be left without a name. To add a named slot you can use the name attribute name="item-start"
on the slot tag. To render a child in that slot simply add the slot attribute to the element that will render as a child. <my-button><span slot="item-start">Label</span></my-button>
. In our simple example of our button it is unnecessary and we just used a self closing slot element.
Attributes/properties with the Prop Decorator
To pass external data or values to a component we use the Prop decorator. This allows us to create an interface for our component that changes how it behaves or renders depending on the input it is given. Props are similar to the Input decorator in Angular. Let’s say we want our button to render in different colors from our theme. We will add a color property that will add a CSS
class to style the button accordingly.
// button.tsx import { Component, h, Prop } from '@stencil/core'; @Component({ tag: 'my-button', styleUrls: ["./button.scss"] }) export class ButtonComponent { @Prop() color: 'primary' | 'accent' = 'primary' render() { const { color } from this; <Host class={ "my-button": true, [`my-${color}-button`]: true }><slot/></Host>; } }
With this simple property, developers can use different styles without having to write a single line of CSS
.
Triggering events with the Event decorator
Events allow components to emit changes within the component. While Stencil does not provide stencil specific events, it does provide a way to create custom DOM events with the Event decorator.
import { Event, EventEmitter } from '@stencil/core'; export class MyComponent { @Event() notifyChanges: EventEmitter<any>; eventHandler(data: any) { notifyChanges.emit(); } }
To listen to the event we can use the addEventListener('notifyChanges', () => {})
method and register the event handler just like any other DOM event. It is that simple.
Learn more about Stencil and how to create components by visiting the Stencil documentation website.