Demoing via storybook

For demoing and showcasing different states of your Web Component, we recommend using storybook.

This is part of the default open-wc recommendation


  • Create API documentation/playground
  • Show documentation (from markdown) with your element
  • Show your source code to copy/paste
  • Helper to setup transpilation for dependencies
  • Setup that works down to IE11


npm init @open-wc
# Upgrade > Demoing


  • yarn add @open-wc/demoing-storybook --dev
  • Copy at minimum the .storybook folder to .storybook
  • If you want to bring along the examples, you may also copy the stories folder.
  • Add the following scripts to your package.json
"scripts": {
  "storybook": "start-storybook -p 9001",
  "storybook:build": "build-storybook -o _site -s storybook-static",
  "site:build": "npm run storybook:build",


Create stories within the stories folder.

npm run storybook

Create a Story

Create an *.stories.js (for example index.stories.js) file within the stories folder.

import {
} from '@open-wc/demoing-storybook';

storiesOf('Demo|Example Element', module)
    'Alternative Header',
    () => html`
      <my-el .header=${'Something else'}></my-el>

Create API documentation/playground

If you have a single element then we can fully generate a usable api documentation/playground. The data will be read from the elements properties. So this should probably be your default story to gives users documentation, api and playground all in one. For additional edge cases you should add more stories.


  • Show your without leaving storybook
  • On the canvas the "knobs" panel is pre selected
  • All the knobs are auto generated from your JavaScript Class

Note: you need to provide the Class (not a node or a template)

import { storiesOf, withKnobs, withClassPropertiesKnobs } from '@open-wc/demoing-storybook';
import readme from '../';

storiesOf('Demo|Example Element', module)
    () => withClassPropertiesKnobs(MyEl),
    { notes: { markdown: readme }, options: { selectedPanel: 'storybooks/knobs/panel' } },

So with a configuration like this you will get this auto generated.

storybook demo animation

For most types this works fine out of the box but if want to provide better knobs you can customize by overriding the properties definitions and using the available knobs.
It creates the knobs by reading static get properties (host properties) and static get _classProperties (inherited properties).
This is currently pretty specific to LitElement - However there is an attribute/properties documentation spec in discussion.

import {
} from '@open-wc/demoing-storybook';

() => withClassPropertiesKnobs(MyEl, {
  overrides: el => [
    // show a color selector
    { key: 'headerColor', fn: () => color('headerColor', el.headerColor, 'Element') },
    // show dropdown
      key: 'type',
      fn: () => select('type', ['small', 'medium', 'large'], el.type, 'Element'),
    // show textarea where you can input json
    { key: 'complexItems', fn: () => object('complexItems', el.complexItems, 'Inherited') },
    // move property to a different group
    { key: 'locked', group: 'Security' },

By default it will create one simple node from the given Class. However for a nicer demo it may be needed to set properties or add more lightdom. You can do so by providing a template. The template must render the custom element to be tested as first root node.

() => withClassPropertiesKnobs(MyEl, {
  template: html`
    <my-el .header=${'override it'}><p>foo</p></my-el>

Show documentation (from markdown) with your element

The documentation will be visible when clicking on "notes" at the top menu.

import readme from '../';

  () => html`
  { notes: { markdown: readme } },

Helper to setup transpilation for dependencies

Whenever you add a dependency that is written in ES modules you will need to enable transpilation for it. Open your configuration and add the new package to the array. Below you see the default settings.

const defaultConfig = require('@open-wc/demoing-storybook/default-storybook-webpack-config.js');

module.exports = ({ config }) => {
  return defaultConfig({ config, transpilePackages: ['lit-html', 'lit-element', '@open-wc'] });

Additional middleware config like a proxy

If you need additional configuration for the storybook dev server you can provide them via a config file .storybook/middleware.js.

// example for a proxy middleware to use an api for fetching data to display
const proxy = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(proxy('/api/', {
    target: 'http://localhost:9010/',