#Trying to make a design system library with Web Components
15 messages · Page 1 of 1 (latest)
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;
},
};
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
Which details, specifically? I'm not all that familiar with vanilla web components (or Lit, for that matter 😅).
Well the 2 imports lines at the top and the render part.
Look at this CodePen for a simple vanilla Web Component example https://codepen.io/craigbuckler/pen/WNpaxPN
Because compared to Lit we do not have an included render function or a JavaScript export then the code for the story is different
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?
Ahh it does work like that too! Which version is preferred then?
The framework is @storybook/web-components-vite
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,
}
};
Ahh alright thank you so much for the detailed answer 👌