Introduction
The Stencil JS idea of writing a component once, and using it everywhere, is something I've been meaning to put into practice for a long time. This post will go over the easy and straightforward process of creating and publishing a simple Stencil component. Then, I'll go over consuming that component in React, Vue, and Angular. Anything more elaborate than the basics will be saved for the conclusion. Here we go!
Creating Stencil JS project
npm init stencil
The CLI will give you a few options. In this example I am going to choose component
, and when prompted, name the project test-demo-seanmclem
. I've included my username in the project name to ensure it's unique. If the name is taken then you will not be able to publish to NPM.
You will also need to change to your projects directory, and install the stencil dependency.
cd test-demo-seanmclem
npm install
The Stencil CLI will create our project, but it will not just be a lone, single component as the name suggests. It will generate a full Stencil project with a components
folder. This folder will contain any components we wish export. The exported components will be included in the production build, published to NPM, and can then each be imported individually into consuming projects. The rest of the Stencil project helps facilitate publishing and consuming the project's components.
Our Stencil Component
The Stencil CLI will add one example component to this components folder. It is called my-component
, and it takes 3 props, first
, middle
, and last
. Each being part of your name. The rendered component takes these inputs and outputs a string like Hello, World!? I'm Your Full Name
.
Run the following to prep the project for publishing
npm run build
Publish to NPM
We're moving quickly because this project and my-component
already have everything we need. Let's publish it to NPM.
You will need to have an account on NPM to proceed. It's simple and free to sign-up if you haven't already. Then login to the CLI
npm login
Follow the prompts to login to the CLI, and then run -
npm publish
If everything went well the CLI should return your new libraries name@version, like mine test-demo-seanmclem@0.0.1
. You can also find this in your npm settings>packages page.
React
Create project
npx create-react-app stencil-in-react
Add component
We will need to go the index.js file and add an import. We will not import a particular component though. Instead we will import a function that will define all our components exported by the Stencil project, and make them available to the react project. This is how native web components, known as Custom Elements, are added to projects. They are typically registered globally as early as possible -rather than imported where ever they are needed.
So we'll add an import to index.js like this:
import { defineCustomElements } from 'test-demo-seanmclem/loader';
And somewhere near the bottom we'll call this function. I'll go over polyfills later.
defineCustomElements();
Next, in app.js you utilize your new custom element
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<my-component first='Your' middle='Full' last='Name'></my-component>
</header>
</div>
);
}
I replaced everything below the img tag in my app.js.
That's pretty much it. You can consume simple Stencil components with simple props in React without doing anything special. More complex components might require extra work for certain props and event listeners. I'd like to do another post on this soon, but that's it for React for now.
Vue
Create project
npm install -g @vue/cli
vue create stencil-in-vue
cd stencil-in-vue
Add component
npm install test-demo-seanmclem
Now we'll add defineCustomElements to one of our main files. Specifically main.js for Vue.
import { defineCustomElements } from 'test-demo-seanmclem/loader';
And again, somewhere near the bottom we'll call this function.
defineCustomElements();
Next, in App.Vue you consume the custom element. You could place it above the HelloWorld component, but I removed it entirely
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<my-component first="Your" middle="Full" last="Name"></my-component>
</div>
</template>
<script>
export default {
name: 'App',
}
</script>
Angular
Create project
npm install -g @angular/cli
ng new stencil-in-angular
cd stencil-in-angular
Add component
npm install test-demo-seanmclem
Now we'll add an import to main.js
import { defineCustomElements } from 'test-demo-seanmclem/loader';
And somewhere near the bottom we'll call this function.
defineCustomElements();
Next, in app.component.html you utilize your new custom element. I replaced pretty much everything in that file.
<div class="content" role="main">
<my-component first="Your" middle="Full" last="Name"></my-component>
</div>
That's it for the basic implementations of Stencil generated web-components in the big 3 frameworks. I'll be writing more on the topic going forward. So feel free to follow me for more.
Conclusion/More Info
Polyfills
These days you might be done supporting IE and legacy browsers. However, Stencil includes some optional polyfills for those that are easy to implement. You would just add an additional applyPolyfills
import to your defineCustomElements
import statement, and wrap your defineCustomElements
call in an async applyPolyfills().then()
.
Read more about that here.
React
As I mentioned react has some complications with more advanced event and prop bindings. Most can be mitigated with a manual wrapping-component, or a react-output-target
. Read more about that here also.
Angular ViewChild
Angular docs call out a specialized way of accessing functions on your component. Which can be useful but not always necessary. Read more about that Here
Thanks for reading!
Top comments (5)
Thanks for this. I returned to stencil and when I do the integration into react etc the methods youdescribe used to work but now they come up with 'defineCustomElements' not exported.
It seems an issue with many. Any ideas?
I'll test it again and see, and then update this post. Still having the issue?
Hi,
After many attemtps it started to work firt with 2.5 then with the standard 2.0.1 version in build.
I don't know what was causing it but it works OK and my love for Stencil has resurged!
hello I am trying to use stencil component in vue3 project. But it does not work according stencil doc and your article. and i can not search solution , Could u update the article, I think this method is oudated.
I really want to pack only the components that i use from my stencil library.
Do you think loader will pack all the components?