#Trying to make a design system library with Web Components

15 messages · Page 1 of 1 (latest)

frail sand
#

All the documentation seems to use Lit, but I want to try if vanilla web components works everywhere before adding a new dependancy.
How can I import my vanilla Web Component into my story?

lyric prism
#

Hi! If you're not using Lit, then you should reference the HTML docs:

https://storybook.js.org/docs/html/writing-stories/introduction

For example:

// Button.stories.ts

import type { Meta, StoryObj } from '@storybook/html';

const meta: Meta = {
  title: 'Button',
};
export default meta;

export const Primary: Story = {
  render: () => {
    const btn = document.createElement('my-button');
    btn.innerText = 'Button';

    btn.className = [
      'my-button',
      'my-button--medium',
      'my-button--primary',
    ].join(' ');

    return btn;
  },
};
frail sand
#

Hi! But then all the web component behavior/script is inside the story not in its own file, so I can't use it outside of Storybook 😕

#

Ahh I think I got it!

import type { Meta, StoryObj } from "@storybook/web-components";
import "./CounterWc";

const meta: Meta = {
    title: "CounterWc",
};
export default meta;

type Story = StoryObj;

export const Primary: Story = {
    render: () => "<counter-wc></counter-wc>",
};
#

That would be helpful to add that in the docs though

lyric prism
#

Which details, specifically? I'm not all that familiar with vanilla web components (or Lit, for that matter 😅).

frail sand
#

Well the 2 imports lines at the top and the render part.

#

Because compared to Lit we do not have an included render function or a JavaScript export then the code for the story is different

lyric prism
#

Thanks for the context!

I'm curious if this works?

import type { Meta, StoryObj } from "@storybook/web-components";
import "./CounterWc";

const meta: Meta = {
    title: "CounterWc",
    component: 'counter-wc',
};
export default meta;

type Story = StoryObj;

export const Primary: Story = {};

If it does, I'll explain why. 🙂

#

Also, what's your framework in .storybook/main.js?

frail sand
#

Ahh it does work like that too! Which version is preferred then?

#

The framework is @storybook/web-components-vite

lyric prism
#

So, that works because Storybook (when using a web-components framework) will automatically create a render function using the element tag name assigned to the component property in your meta. And that render function has exactly the same shape as the one you were providing above.

(The only difference from Lit is that you must import the component to register it, whereas Lit handles that for you.)

We recommend taking advantage of the implicit render function whenever possible. However, due to how web components are implemented, you cannot pass arbitrary args (including those in controls) and must define an explicit render function for that case. For example:

import type { Meta, StoryObj } from "@storybook/web-components";
import "./CounterWc";

const meta: Meta = {
    title: "CounterWc",
    component: 'counter-wc',
};
export default meta;

type Story = StoryObj;

export const Primary: Story = {
  args: {
    value: 10,
  }
};

That value arg will not be passed on to your CounterWc component. Instead you need to define a render function:

import type { Meta, StoryObj } from "@storybook/web-components";
import "./CounterWc";

const meta: Meta = {
    title: "CounterWc",
    component: 'counter-wc',
};
export default meta;

type Story = StoryObj;

export const Primary: Story = {
  render: (args) => `<counter-wc value="${args.value}"></counter-wc>`,
  args: {
    value: 10,
  }
};
frail sand
#

Ahh alright thank you so much for the detailed answer 👌