Exploring Storybook with Sveltekit

2023-06-20

Challenge

I want to use Storybook with Svelte for my svelte component library. I have something that works, but I would like to take something off my plate for maintenance.

Today I’ll look into the implementation of Storybook for Svelte and see if it suites what I want

Installation

I’m going to try to add to this to my sveltekit kuix project

pnpm dlx storybook@latest init

Now try to run it…

pnpm run storybook

Did it work?

Nope. No builder configured error. Fun.

Looks like there is a package to help with specific sveltekit implementation:

https://github.com/storybookjs/storybook/tree/next/code/frameworks/sveltekit

Round 2 installation

pnpm dlx storybook@latest init

Oh wait it looks like it was already detecting it and using the svelkit prackage but still failing.

Dug a little further, looks like it configured it for @storybook/sveltekit but the package wasn’t installed

>pnpm install -D @storybook/sveltekit

Run it?

>pnpm run storybook

Beauty.

Now what?

So based on the preset items, a folder is now generated in the src folder called stories .

And in this folder you have a .svelte component file, and .stories.ts file for the doc configs

My components live in the lib folder as this is this the folder that is exported into a package from svelte-pacakge . That is okay because the stories just import the component. However, I do see the appeal of co-locating the story files with the component… but for now lets keep the components where they are.

In my lib, I have a very a basic Button component.

<script>
	/**
	 * @type {boolean}
	 * @default false
	 */
	export let disabled = false;

	/**
	 * @type {'regular' | 'small' | 'large'}
	 * @default 'regular'
	 */
	export let size = 'regular';
</script>

<style>
	.regular {
		@apply px-2.5 py-1.5;
	}
</style>

<button class="bg-blue-500 rounded-md {size}" {disabled}>
	<slot />
</button>

I’m going to create a Button.stories.ts file to configure the stories for this component

import Button from '$lib/prime/Button.svelte';

const meta = {
	title: 'example/Button',
	component: Button,
	tags: ['autodocs'],
	argTypes: {
		size: {
			control: { type: 'select' },
			options: ['small', 'regular', 'large']
		}
	}
} satisfies Meta<Button>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Primary: Story = {
	args: {
		disabled: false
	}
};

Just following the provided examples, it works rendered. Except, my Button relies on the slot to render the label, so nothing is being shown.

Can I configure the example slot?

Cannot do this with the default configuration. However, there is a package called @storybook/addon-svelte-csf that allows you to write the stories in Svelte syntax.

$ pnpm install -D @storybook/addon-svelte-csf

Then go into ./storybook/main.ts and add it to the addons

...
addons: [..., '@storybook/addon-svelte-csf'],
...

Also need to update the main.ts configuration to look for .stories.svelte files

stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx|svelte)'],

Okay so it works. Great.

Conclusion

Okay to speed right to the conclusion, I ended this endeavor quite quickly. I got around to trying to write the docs and using the .mdx extension and it just became a mess.

You can embed the code into the docs, but you can’t read the source code in the snippet because its trapped behind some proxy.

Looks like more work needs to be put in to make it more usable with svelte. Perhaps in another year. I could try to hack my way through it but it just seems like you’re jumping through hoops to force something that is built for React.