DEV Community

Seanmclem
Seanmclem

Posted on • Updated on

Consuming a Stencil JS component in several frameworks

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!

Discussion (4)

Collapse
iwswordpress profile image
Craig West

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?

Collapse
seanmclem profile image
Seanmclem Author

I'll test it again and see, and then update this post. Still having the issue?

Collapse
iwswordpress profile image
Craig West

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!

Collapse
jackzhoumine profile image
jackzhoumine

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.