In this little tutorial we learn how to add Web Components created with Stencil to a Storybook setup. Stencil is a framework which let us write Web Components in a JSX-style syntax similar to React's class-components. It then compiles it to native Web Components code to make it usable in the browser.
1. Create a new Stencil project
First we initialize a new Stencil project from scratch with Stencil's handy CLI tool. It generates an initial project structure for us where we can simply add new components later on.
Note: If you already have a Stencil project you can skip this step and go straight to Step 2.
npm init stencil
In the following dialog Stencil asks us to pick a project type. Since we want to generate a library of Web Components choose the component
option here and continue.
In the last step of the project generator we choose a name for the project, for simplicity we name it storybook-stencil-example
.
Now we navigate into our newly created stencil project and install the dependencies:
cd storybook-stencil-example # Navigate into project dir
npm i # Install dependencies
2. Add Storybook to the project
Because Stencil components are compiled to Web Components we simply can use Storybook for HTML project type here:
# Bootstrap storybook
npx -p @storybook/cli sb init --type html
# Install additional dependencies for our setup
npm i --save-dev \
write-file-webpack-plugin \
copy-webpack-plugin \
@storybook/addon-notes
Now we need to make some changes to the default configuration from Storybook. We
// .storybook/main.js
const fs = require('fs');
const path = require('path');
const CopyPlugin = require('copy-webpack-plugin');
const WriteFilePlugin = require('write-file-webpack-plugin');
const OUTPUT_DIR = '../dist';
// Stencil names the project entry the same as the project
// Look for the file `dist/<your-project-name>.js` to find out what to insert here
const PROJECT_NAME = 'storybook-stencil-example';
module.exports = {
stories: ['../src/**/*.stories.js'],
addons: ['@storybook/addon-notes/register'],
// Custom webpack config to tell Storybook where to find the compiled files from Stencil
async webpackFinal(config) {
config.entry.push(path.join(__dirname, OUTPUT_DIR, `${PROJECT_NAME}.js`));
fs.readdirSync(path.join(__dirname, OUTPUT_DIR, 'collection/components')).map(file => {
jsFilePath = path.join(__dirname, OUTPUT_DIR, `collection/components/${file}/${file}.js`);
try {
if (fs.existsSync(jsFilePath)) {
config.entry.push(jsFilePath);
}
} catch (err) {
console.error(err);
}
// Add CSS
let cssFilePath = path.join(
__dirname,
OUTPUT_DIR,
`collection/components/${file}/${file}.css`
);
try {
if (fs.existsSync(cssFilePath)) {
config.entry.push(cssFilePath);
}
} catch (err) {
console.error(err);
}
});
// Add all static files to Storybook
config.plugins.push(
new CopyPlugin([
{
from: '**/*',
to: './',
context: 'dist',
},
])
);
// Write the files to disk and not to memory
config.plugins.push(new WriteFilePlugin());
return config;
},
};
3. Create our first story
The Stencil project setup has already added a sample component for us named my-component
. So let's create our first story for this component. Inside the component folder add a new file my-component.stories.js
:
src/
└── components/
└── my-component/
├── my-component.css
├── my-component.e2e.ts
├── my-component.stories.js # <-- Add the file here
├── my-component.tsx
└── readme.md
...
Of course we could also write the stories in TypeScript because stencil already relies on it but to keep things simple we use plain JavaScript for now.
// my-component.stories.js
import readme from './readme.md';
export default {
title: 'My Component',
parameters: {
markdown: readme,
},
};
export const Default = () => `
<my-component first="Millie" middle="Bobby" last="Brown"></my-component>
`;
Importing the auto-generated readme.md
from Stencil gives us a free documentation of our component which can also be showed in Storybooks "Notes" tab of the component.
4. Development workflow
To make the best use of Stencil and Storybook, both support a live-reload development workflow so that we can see changes we make to our Stencil components directly in Storybook without reloading the browser.
To make this work we start the Stencil dev server and the Storybook dev server parallel in two different terminals:
# Terminal 1 - Run Stencil compiler in watch mode
npm start
# Terminal 2 - Run Storybook
npm run storybook
Now the final result should now look like this in the browser. The canvas gives us a preview of our component while the note tab holds the documentation of the component itself.
You can also see a live-demo of the Storybook here: https://ofhouse.github.io/storybook-stencil-example
This is only a basic setup guide for Stencil and Storybook, to make use of Storybook's advanced features like Knobs or Actions I will add a second tutorial shortly. So follow me for more content!
This guide was made possible by the work of of Bobby Johnson. He has made a really nice video of the whole process of his Stencil and Storybook setup here: Using StencilJS with Storybook on YouTube
You can find the whole example project from this tutorial in the following repository:
ofhouse / storybook-stencil-example
Example project which uses Stencil components in Storybook.
Storybook Stencil Example
This is a starter project for building a Web Component library with Stencil and Storybook.
Getting Started
To start clone this repo into a new directory and run the following commands:
npm install
npm start
For a step-by-step tutorial how to recreate this from scratch you can follow this series of blog posts:
Features
Author
License
MIT - see LICENSE for details.
Top comments (4)
Hello,
Thank you for this article. For information, with newer versions of stencil and storybook I had to make some adjustments in order to make it works.
The Webpack config uses the
collection
folder that seems to not be created by default with thenpm start
with stencil 1.12. I had to modify the start script in order to make it build es5 files in dev mode :The Storybook Notes plugin (5.3.18) documentation gives a different object in order to use markdown. You need a
notes
node in the story parameter.Hope it can help. Have a good day.
hey, great article, also with the newer version of
copy-webpack-plugin
is necessarypatterns
node in storybook config.storybook/main.js
This article is very helpful. Thank you so much for this.
There are a few more things to update.
The latest version of
copy-webpack-plugin
(v7.0.0) will not work. So, I had to downgrade it to v6.2.1.And stencil build doesn't automatically generate
dist/<your-project-name>.js
. It will generatedist/<your-project-name>/<your-project-name>.esm.js
only. I had to addbuildEs5: true
in stencil.config.please share full info here.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.