Making Framework Agnostic Web Components with StencilJS

The Problem

The problem with React, Angular, Vue and Svelte that as frameworks if you create a component it can’t be used in another framework (at least not in a way that would make workflow easier or bundles smaller). So if your company has multiple teams working across different frameworks it may limit the transportability of their work.

Install

Fun Fact: if you type a command after “npm init” such as “npm init foo” it is translated to “npx create-foo”. So essentially “npm init react-app” is the same as “npx create-react-app” something to remember when you name your next scaffolding tool. So to create a new Stencil Application run the following command.

Run Dev Server

To run your dev server just run npm start and you’ll see the basic shell of an app.

Folder Structure

src

Everything you need to work with like in other frameworks is in the src folder.

ASSETS

Place images and other assets here.

COMPONENTS

Here is where all your components live

GLOBAL

this is where you’ll find the global css, and a global ts file to right logic that should occur on Application startup.

www

When you run the build command, npm run build The deployable output will be in this folder.

Anatomy of a Component

By default you’ll notice that all components have a two-part name (part1-part2) this is to prevent collision with native HTML tags so you are required to follow this convention.

app-component.css

The CSS file to write CSS scoped to that component

app-component.e2e.ts

File for writing tests if you choose to do testing

app-component.ts

This is the actual component file, notice this is a TypeScript file as Stencil requires writing your components in Typescript.

Creating a new component

Run the command…

import { Component, Host, h } from '@stencil/core';@Component({
tag: 'app-button',
styleUrl: 'app-button.css',
shadow: true,
})
export class AppButton {
render() {
return (
<Host>
<slot></slot>
</Host>
);
}
}

State and Props

So if we can use JSX like React but we are using Typescript and Decorators like angular… how are State and Props handled? The way it works is you’ll declare any state and props as individual class properties using the Props and State decorators. Try out the following in app-button.

import { Component, Host, h, Prop, State } from '@stencil/core';@Component({
tag: 'app-button',
styleUrl: 'app-button.css',
shadow: true,
})
export class AppButton {
@Prop() word:string;
@State() count:number = 1;
render() {
return (
<Host>
<button>{this.word} {this.count}</button>
</Host>
);
}
}
@Component({
tag: 'app-home',
styleUrl: 'app-home.css',
shadow: true,
})
export class AppHome {
render() {
return (
<div class="app-home">
<p>
Welcome to the Stencil App Starter. You can use this starter to build entire apps all with web components using Stencil! Check out our docs on{' '}
<a href="https://stenciljs.com">stenciljs.com</a> to get started.
</p>
<app-button word="Click Me"/> <stencil-route-link url="/profile/stencil">
<button>Profile page</button>
</stencil-route-link>
</div>
);
}
}

Events

While there is a Listen decorator you can use there is also the ability to just add an event in your JSX like you would in React.

import { Component, Host, h, Prop, State } from '@stencil/core';@Component({
tag: 'app-button',
styleUrl: 'app-button.css',
shadow: true,
})
export class AppButton {
@Prop() word: string;
@State() count: number = 1;
render() {
return (
<Host>
<button
onClick={() => {
this.count += 1;
console.log(this.count);
}}
>
{this.word} {this.count}
</button>
</Host>
);
}
}

Keep On Learning

This should be enough to keep you learning, checkout the documentation at StencilJS to learn more about other cool features:

  • the stencil router

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alex Merced Coder

Alex Merced Coder

59 Followers

Alex Merced is a Developer Advocate for Dremio and host of the Web Dev 101 and Datanation Podcasts.