Skip to content

Integrating Storybook with SvelteKit, TypeScript, and SCSS

Introduction

Storybook is a great tool for testing, and visualizing your components in different states.

Storybook allows teams to collaborate to develop durable UIs in isolation. It allows users to implement reusable components without fussing with data, APIs, or business logic.

In this article, we will discuss how to integrate Storybook in a SvelteKit project with TypeScript, and SCSS support.

Zero-config set up

To get started, run the following in the root of an existing Svelte project:

    npx sb@next init

This detects the project type, installs @storybook/svelte, and adds some sample files to demonstrate the basics of Storybook. Running npm run storybook gives you the following zero-config set up on http://localhost:6006

Example Browse All Stories

Project Structure

Our project structure is already set up by SvelteKit, and Storybook initialization has created a .storybook folder. Still, we need to make some changes to the Storybook file extension, since our project is in TypeScript. This is a snippet of the folders in our project:

    ├── .storybook
        ├── main.cjs
        ├── preview.js
        └── preview-head.html
    ├── vite.config.ts
    └── src

Add SCSS support

To add SCSS support, we need the @storybook/preset-scss addon.

Install sass, @storybook/preset-scss, and other relevant style loaders.

npm i -D sass @storybook/preset-scss css-loader sass-loader style-loader

Navigate to storybook/main.cjs

Add @storybook/preset-scss to the addons' array.

	addons: [
		'@storybook/addon-links',
		'@storybook/addon-essentials',
		'@storybook/addon-interactions',
		'@storybook/preset-scss' // add here
	],

Add $lib alias support

Navigate to .storybook/main.cjs.

Import mergeConfig from Vite. This deeply merges two Vite configs.

Import path. The path module provides utilities for working with file, and directory paths.

Finally, we need to resolve the $lib to point to ../src/lib for Storybook.

async viteFinal(config) {
    return mergeConfig(config, {
        resolve: {
            alias: { $lib: path.resolve(__dirname, '../src/lib') }
        }
    });
}

Your .storybook/main.cjs should contain the following:

// .storybook/main.cjs

const { mergeConfig } = require("vite");
const path = require("path");

module.exports = {
  stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
    "@storybook/preset-scss",
  ],
  framework: {
    name: "@storybook/sveltekit",
    options: {},
  },
  docs: {
    autodocs: "tag",
  },
  async viteFinal(config) {
    return mergeConfig(config, {
      resolve: {
        alias: { $lib: path.resolve(__dirname, "../src/lib") },
      },
    });
  },
};

Creating Stories

We will start by creating a Greeting.svelte file that receives a message from our server.

    <script lang="ts">
        export let message: string;
    </script>

    <div class="fetch-container">
        <header>
            <h1>SvelteKit Fetch Data from API</h1>
        </header>
        <div>
            Message: {message}
        </div>
    </div>

    <style lang="scss">
        .fetch-container {
            text-align: center;

            header {
              margin: 1.25rem auto;
              width: 40%;

              h1 {
                padding: 0.9375rem 0;
                font-size: 2rem;
                text-align: center;
                border-bottom: 5px solid #1d4ed8;
              }
            }

            div {
              font-size: 1.2rem;
              display: flex;
              justify-content: center;
            }
        }
    </style>

Then a Greeting.stories.ts with a message argument:

    import Greeting from './Greeting.svelte';

    export default {
        component: Greeting,
        title: 'Example/Greeting',
        excludeStories: /.*Data$/,
        argTypes: {
            message: 'from Storybook',
        },
    };

    const Template = ({ ...args }) => ({
        Component: Greeting,
        props: args,
    });

    export const Default = Template.bind({});
        Default.args = {
        message: 'from This Dot’,
    };

Simply run npm run storybook to see if your story is running:

Storybook-example

You can edit the argument to test different messages.

Conclusion

In this article, we learned how to set up Storybook in a SvelteKit project, and created our first story.

If you are looking to bootstrap your next project, check out our starter kit that uses SvelteKit and SCSS.

Thanks for reading!

If you have any questions or run into any trouble, feel free to reach out on Twitter.