← BackJul 02, 2023 - 3 min read

Set up Storybook in a Stencil project

post cover image

A quick tutorial on how to set up storybook in a new stencil project. Configuring the JSX support and showing the events in the action tab

Setup Storybook in a Stencil project was not as easy as I expected. So I documented here the main steps I took to setup my project. Hope this can be useful to others in need.

Beginning with a Stencil application created, run the init script for the Storybook:

1npx -p @storybook/cli sb init --type=html 2

This asks to set up using Webpack 5 or Vite. Both seem to work fine.

Now we need to allow Storybook to run my web components created with Stencil, So inside the .storybook/preview.js add the following code:

1import { defineCustomElements } from '../loader'; 2 3defineCustomElements(); 4

This will allow us to use the tag created for our components inside the Storybook. Also in this file, you can import the Stencil's global.css file:

1import '../src/global/global.css'; 2

Now the basis of the setup is almost done. but there is one small problem. This loader folder that we imported does not exist yet. This folder is created at the build time of our application

so to create this folder we can run the build on watch mode:

1npx stencil build --watch 2

this way every change that we in our components will reflect on the Storybook file (keep in mind that sometimes you need to refresh the Storybook page, especially with CSS).

Now with the Stencil build running, we can start the Storybook in a new terminal tab with the command:

1npm run storybook 2

Great. now we can write our first story. Like with every other Storybook setup, we can place our .stories file into any folder that we want. I like to keep my stories in the same folder as my component, but you are free to follow other structures.

The story should be written using pure HTML into a string (for now at least). So my first story looked like this:

1export default { 2 title: 'Atoms/Button', 3 tags: ['autodocs'], 4 argTypes: { 5 label: { control: 'text' }, 6 size: { 7 options: ['small', 'medium', 'large'], 8 control: { type: 'radio' }, 9 }, 10 11 }, 12}; 13 14const Template = args => `<my-button label="${args.label}" variant="${args.variant}" size="${args.size}"></my-button>`; 15 16export const primary = Template.bind({}); 17primary.args = { 18 label: 'Click me', 19 variant: 'primaryFilled', 20 size: 'medium', 21}; 22

This works fine, but we can set up the JSX syntax pretty easily. So all we need to do is to set up Babel to handle this for us. So first we need to install some libs:

1npm i --save-dev @babel/plugin-syntax-jsx @babel/plugin-transform-react-jsx jsx-dom 2

Now add the plugins we just installed to the .babelrc file on the root of our project:

1 "plugins": [ 2 "@babel/plugin-syntax-jsx", 3 [ 4 "@babel/plugin-transform-react-jsx", 5 { 6 "pragma": "h" 7 } 8 ] 9 ] 10

now at our story, we can use the JSX syntax just by importing the h from the jsx-dom library.

1import { h } from 'jsx-dom'; 2 3export default { 4 title: 'Atoms/Button', 5 tags: ['autodocs'], 6 argTypes: { 7 label: { control: 'text' }, 8 size: { 9 options: ['small', 'medium', 'large'], 10 control: { type: 'radio' }, 11 }, 12 }, 13}; 14 15const Template = args => <plx-button label={args.label} variant={args.variant} size={args.size}></plx-button>; 16 17export const primary = Template.bind({}); 18primary.args = { 19 label: 'Click me', 20 variant: 'primaryFilled', 21 size: 'medium', 22}; 23

much better. The last thing that I struggle with was setting up the events to show up in the actions tab on the Storybook page. The way I did this was to set up the withActions decorator from the @storybook/addon-actions package. So first, to install run this command:

1npm i -D @storybook/addon-actions 2

and then we can use it like this:

1export default { 2 title: 'Atoms/Button', 3 tags: ['autodocs'], 4 argTypes: { 5 // ... 6 }, 7 decorators: [withActions], 8 9 parameters: { 10 actions: { 11 handles: ['click', 'mouseover', 'mouseout'], 12 }, 13 }, 14}; 15

Now the events click, mouseover, and mouseout is logged into the Storybook. Exactly as expected.

Now we have a basic setup of Storybook in a Stencil build. Now you can keep enhancing this setup by adding more plugins to fit your need.