Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@storybook/addon-svelte-csf

storybookjs412.1kMIT5.0.10TypeScript support: included

Allows to write stories in Svelte syntax

storybook-addons, csf, svelte

readme

Svelte CSF

This Storybook addon allows you to write Storybook stories using the Svelte language instead of ESM that regular CSF is based on.

npx storybook@latest add @storybook/addon-svelte-csf

Using the Svelte language makes it easier to write stories for composed components that rely on snippets or slots, which aren't easily re-created outside of Svelte files.

🐣 Getting Started

[!TIP] If you've initialized your Storybook project with Storybook version 8.2.0 or above, this addon is already set up for you!

[!IMPORTANT]
Not running the latest and greatest versions of Storybook or Svelte? Be sure to check the version compatibility section below.

The easiest way to install the addon is with storybook add:

npx storybook@latest add @storybook/addon-svelte-csf

You can also add the addon manually. First, install the package:

npm install --save-dev @storybook/addon-svelte-csf

Then modify your main.ts Storybook configuration to include the addon and include *.stories.svelte files:

export default {
-  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
+  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx|svelte)'],
  addons: [
+    '@storybook/addon-svelte-csf',
    ...
  ],
  ...
}

Restart your Storybook server for the changes to take effect.

🐓 Usage

[!NOTE] The documentation here does not cover all of Storybook's features, only the aspects that are specific to the addon and Svelte CSF. We recommend that you familiarize yourself with Storybook's core concepts at https://storybook.js.org/docs.

The examples directory contains examples describing each feature of the addon. The Button.stories.svelte example is a good one to get started with. The Storybook with all the examples is published on Chromatic here.

Svelte CSF stories files must always have the .stories.svelte extension.

Defining the meta

All stories files must have a "meta" (aka. "default export") defined, and its structure follows what's described in the official docs on the subject. To define the meta in Svelte CSF, call the defineMeta function within the module context, with the meta properties you want:

<script module>
  //    👆 notice the module context, defineMeta does not work in a regular <script> tag - instance
  import { defineMeta } from '@storybook/addon-svelte-csf';

  import MyComponent from './MyComponent.svelte';

  //      👇 Get the Story component from the return value
  const { Story } = defineMeta({
    title: 'Path/To/MyComponent',
    component: MyComponent,
    decorators: [
      /* ... */
    ],
    parameters: {
      /* ... */
    },
  });
</script>

defineMeta returns an object with a Story component (see Defining stories below) that you must destructure out to use.

Defining stories

To define stories, you use the Story component returned from the defineMeta function. Depending on what you want the story to contain, there are multiple ways to use the Story component. Common for all the use case is that all properties of a regular CSF story are passed as props to the Story component, with the exception of the render function, which does not have any effect in Svelte CSF.

All story requires either the name prop or exportName prop.

[!TIP] In versions prior to v5 of this addon, it was always required to define a template story with the <Template> component. This is no longer required and stories will default to render the component from meta if no template is set.

Plain Story

If your component only accepts props and doesn't require snippets or slots, you can use the simple form of defining stories, only using args:

<Story name="Primary" args={{ primary: true }} />

This will render the component defined in the meta, with the args passed as props.

With children

If your component needs children, you can pass them in directly to the story, and they will be forwarded to your component:

<Story name="With Children">I will be the child of the component from defineMeta</Story>

Static template

If you need more customization of the story, like composing components or defining snippets, you can set the asChild prop on the Story. Instead of forwarding the children to your component, it will instead use the children directly as the story output. This allows you to write whatever component structure you desire:

<Story name="Composed" asChild>
  <MyComponent>
    <AChild label="Hello world!" />
  </MyComponent>
</Story>

[!IMPORTANT]
This format completely ignores args, as they are not passed down to any of the child components defined. Even if your story has args and Controls, they won't have an effect. See the snippet-based formats below.

Inline snippet

If you need composition/snippets but also want a dynamic story that reacts to args or the story context, you can define a template snippet in the Story component:

<Story name="Simple Template" args={{ simpleChild: true }}>
  {#snippet template(args)}
    <MyComponent {...args}>Component with args</MyComponent>
  {/snippet}
</Story>

Shared snippet

Often your stories are very similar and their only differences are args or play-functions. In this case it can be cumbersome to define the same template snippet over and over again. You can share snippets by defining them at the top-level and passing them as props to Story:

{#snippet template(args)}
  <MyComponent {...args}>
    {#if args.simpleChild}
      <AChild data={args.childProps} />
    {:else}
      <ComplexChildA data={args.childProps} />
      <ComplexChildB data={args.childProps} />
    {/if}
  </MyComponent>
{/snippet}

<Story name="Simple Template" args={{ simpleChild: true }} {template} />

<Story name="Complex Template" args={{ simpleChild: false }} {template} />

You can also use this pattern to define multiple templates and share the different templates among different stories.

Default snippet

If you only need a single template that you want to share, it can be tedious to include {template} in each Story component. Like in th example below:

<Story name="Primary" args={{ variant: 'primary' }} {template} />
<Story name="Secondary" args={{ variant: 'secondary' }} {template} />
<Story name="Tertiary" args={{ variant: 'tertiary' }} {template} />
<!-- ... more ... -->
<Story name="Denary" args={{ variant: 'denary' }} {template} />

Similar to regular CSF, you can define a meta-level render-function, by referencing your default snippet in the render property of your defineMeta call:

<script module>
  import { defineMeta } from '@storybook/addon-svelte-csf';
  import MyComponent from './MyComponent.svelte';

  const { Story } = defineMeta({
    render: template,
    //      👆 the name of the snippet as defined below (can be any name)
  });
</script>

{#snippet template(args)}
  <MyComponent {...args}>
    {#if args.simpleChild}
      <AChild data={args.childProps} />
    {:else}
      <ComplexChildA data={args.childProps} />
      <ComplexChildB data={args.childProps} />
    {/if}
  </MyComponent>
{/snippet}

<Story name="Simple Children" args={{ simpleChild: true }} />

<Story name="Complex Children" args={{ simpleChild: false }} />

Stories can still override this default snippet using any of the methods for defining story-level content.

[!NOTE] Svelte has the limitation, that you can't reference a snippet from a <script module> if it reference any declarations in a non-module <script> (whether directly or indirectly, via other snippets). See svelte.dev/docs/svelte/snippet#Exporting-snippets

Custom export name

Behind-the-scenes, each <Story /> definition is compiled to a variable export like export const MyStory = ...;. In most cases you don't have to care about this detail, however sometimes naming conflicts can arise from this. The variable names are simplifications of the story names - to make them valid JavaScript variables.

This can cause conflicts, eg. two stories with the names "my story!" and "My Story" will both be simplified to MyStory.

You can explicitly define the variable name of any story by passing the exportName prop:

<Story exportName="MyStory1" name="my story!" />
<Story exportName="MyStory2" name="My Story" />

At least one of the name or exportName props must be passed to the Story component - passing both is also valid.

Accessing Story context

If for some reason you need to access the Story context (e.g. for mocking) while rendering the story, then <Story />'s attribute template snippet provides an optional second argument.

<Story name="Default">
  {#snippet template(args, context)}
   <!--                    👆 use the optional second argument to access Story context -->
     <MyComponent {...args}>
  {/snippet}
</Story>

TypeScript

Story template snippets can be type-safe when necessary. The type of the args are inferred from the component or render property passed to defineMeta.

If you're just rendering the component directly without a custom template, you can use Svelte's ComponentProps type and StoryContext from the addon to make your template snippet type-safe:

<script module lang="ts">
  import { defineMeta, type StoryContext } from '@storybook/addon-svelte-csf';
  import { type ComponentProps } from 'svelte';

  import MyComponent from './MyComponent.svelte';

  const { Story } = defineMeta({
    component: MyComponent,
  });

  type Args = ComponentProps<MyComponent>;
</script>

{#snippet template(args: Args, context: StoryContext<typeof Layout>)}
  <MyComponent {...args} />
{/snippet}

If you use the render-property to define a custom template that might use custom args, the args will be inferred from the types of the snippet passed to render. This is especially useful when you're converting primitive args to snippets:

<script module lang="ts">
  import { defineMeta, type StoryContext } from '@storybook/addon-svelte-csf';
  import { type ComponentProps } from 'svelte';

  import MyComponent from './MyComponent.svelte';

  const { Story } = defineMeta({
    component: MyComponent,
    render: template, // 👈 args will be inferred from this, which is the Args type below
    argTypes: {
      children: {
        control: 'text',
      },
      footer: {
        control: 'text',
      },
    },
  });

  type Args = Omit<ComponentProps<MyComponent>, 'children' | 'footer'> & {
    children: string;
    footer?: string;
  };
  // OR use the Merge helper from the 'type-fest' package:
  type Args = Merge<
    ComponentProps<MyComponent>,
    {
      children: string;
      footer?: string;
    }
  >;
</script>

<!--                👇 you need to omit 'children' from args to satisfy Svelte's constraints -->
{#snippet template({ children, ...args }: Args, context: StoryContext<typeof MyComponent>)}
  <MyComponent {...args}>
    {children}
    {#snippet footer()}
      {args.footer}
    {/snippet}
  </MyComponent>
{/snippet}

See the Types.stories.svelte examples on how to use complex types properly.

Legacy API

Version 5 of the addon changes the API from v4 in key areas, as described above. However a feature flag has been introduced to maintain support for the <Template>-based legacy API as it was prior to v5.

To enable supoprt for the legacy API, make the following change to your main Storybook config:

export default {
  addons: [
-    '@storybook/addon-svelte-csf',
+    {
+      name: '@storybook/addon-svelte-csf',
+      options: {
+         legacyTemplate: true
+    },
    ...
  ],
  ...
}

This can make the overall experience slower, because it adds more transformation steps on top of the existing ones. It should only be used temporarily while migrating to the new API. It's highly likely that the legacy support will be dropped in future major versions of the addon.

The legacy support is not bullet-proof, and it might not work in all scenarios that previously worked. If you're experiencing issues or getting errors after upgrading to v5, try migrating the problematic stories files to the modern API.

Version compatibility

latest

Version 5 and up of this addon requires at least:

Dependency Version
Storybook v8.0.0
Svelte v5.0.0
Vite v5.0.0
@sveltejs/vite-plugin-svelte v4.0.0

[!IMPORTANT] As of v5 this addon does not support Webpack.

v4

npm install --save-dev @storybook/addon-svelte-csf@^4

Version 4 of this addon requires at least:

  • Storybook v7
  • Svelte v4
  • Vite v4 (if using Vite)
  • @sveltejs/vite-plugin-svelte v2 (if using Vite)

v3

npm install --save-dev @storybook/addon-svelte-csf@^3

Version 3 of this addon requires at least:

  • Storybook v7
  • Svelte v3

v2

npm install --save-dev @storybook/addon-svelte-csf@^2

If you're using Storybook between v6.4.20 and v7.0.0, you should use version ^2.0.0 of this addon.

🤝 Contributing

This project uses pnpm for dependency management.

  1. Install dependencies with pnpm install
  2. Concurrently start the compilation and the internal Storybook with pnpm start.
  3. Restarting the internal Storybook is often needed for changes to take effect.

changelog

v5.0.10 (Fri Oct 03 2025)

🐛 Bug Fix

Authors: 1


v5.0.9 (Thu Oct 02 2025)

🐛 Bug Fix

Authors: 1


v5.0.8 (Wed Aug 20 2025)

🐛 Bug Fix

  • Expand version range storybook to be compatible with SB10 #326 (@ndelangen)

Authors: 1


v5.0.7 (Mon Jul 14 2025)

🐛 Bug Fix

Authors: 1


v5.0.6 (Fri Jul 04 2025)

🐛 Bug Fix

  • Fix raw code not being injected with Svelte v5.35.1+ #321 (@JReinhold)

Authors: 1


v5.0.5 (Thu Jul 03 2025)

🐛 Bug Fix

Authors: 1


v5.0.4 (Tue Jun 24 2025)

🐛 Bug Fix

Authors: 1


v5.0.3 (Wed May 28 2025)

🐛 Bug Fix

  • Drop support for 9.0.0 prereleases, add support for 9.1.0 prereleases #312 (@JReinhold)

Authors: 1


v5.0.2 (Wed May 28 2025)

🐛 Bug Fix

Authors: 2


v5.0.1 (Sun May 18 2025)

🐛 Bug Fix

  • fix: Allow user-defined local variable meta in stories #309 (@xeho91)

Authors: 1


v5.0.0 (Tue May 06 2025)

Release Notes

Breaking: Add support for render in defineMeta, replacing setTemplate-function (#295)

setTemplate-function removed in favor of render in defineMeta

The setTemplate-function has been removed. Instead reference your default snippet with the render-property in defineMeta:

<script module>
- import { defineMeta, setTemplate } from '@storybook/addon-svelte-csf';
+ import { defineMeta } from '@storybook/addon-svelte-csf';
  import MyComponent from './MyComponent.svelte';

  const { Story } = defineMeta({
    /* ... */
+   render: template
  });
</script>

-<script>
-  setTemplate(template);
-</script>

{#snippet template(args)}
  <MyComponent {...args}>
    ...
  </MyComponent>
{/snippet}

<Story name="With Default Template" />

This new API achieves the same thing, but in a less verbose way, and is closer aligned with Storybook's regular CSF. 🎉

[!IMPORTANT] There is currently a bug in the Svelte language tools, which causes TypeScript to error with TS(2448): Block-scoped variable 'SNIPPET_NAMAE' used before its declaration.. Until that is fixed, you have to silent it with //@ts-ignore or //@ts-expect-error. See https://github.com/sveltejs/language-tools/issues/2653

Breaking: Rename children prop to template, require asChild for static stories (#228)

This release contains breaking changes related to the children-API. The legacy API stays as-is to maintain backwards compatibility.

children renamed to template

The children-prop and children-snippet on Story has been renamed to template, to align better with Svelte's API and not be confused with Svelte's default children-snippet. If you have any stories using the children prop or snippet, you need to migrate them:


{#snippet template()}
  ...
{/snippet}

-<Story name="MyStory" children={template} />
+<Story name="MyStory" template={template} />

<Story name="MyStory">
-  {#snippet children(args)}
+  {#snippet template(args)}
    <MyComponent />
  {/snippet}
</Story>

Story children are now forwarded to components

Previously, to define static stories, you would just add children to a Story, and they would be the full story. To make it easier to pass children to your components in stories, the children are now instead forwarded to the component instead of replacing it completely.

Previously:

<script module>
  import { defineMeta } from '@storybook/addon-svelte-csf';

  import MyComponent from './MyComponent.svelte';

  const { Story } = defineMeta({
    component: MyComponent,
  });
</script>

<!--
This story renders:

This would be the full story, ignoring the MyComponent in the meta
-->
<Story name="Static Story">
  This would be the full story, ignoring the MyComponent in the meta
</Story>

Now:

<script module>
  import { defineMeta } from '@storybook/addon-svelte-csf';

  import MyComponent from './MyComponent.svelte';

  const { Story } = defineMeta({
    component: MyComponent,
  });
</script>

<!--
This story renders:

<MyComponent>
  This is now forwarded to the component
</MyComponent>
-->
<Story name="MyComponent children">This is now forwarded to the component</Story>

To get the same behavior as previously, a new asChild boolean prop has been introduced on the Story component. asChild is a common prop in UI libraries, where you want the children to be the output, instead of just being children of the Component. By adding that you can get the old behavior back, when you need more control over what the story renders:

<script module>
  import { defineMeta } from '@storybook/addon-svelte-csf';

  import MyComponent from './MyComponent.svelte';

  const { Story } = defineMeta({
    component: MyComponent,
  });
</script>

<!--
This story renders:

This is the full story, ignoring the MyComponent in the meta
-->
<Story name="Static Story" asChild>
  This is the full story, ignoring the MyComponent in the meta
</Story>

Require Storybook 8.2.0 and above, support Storybook 9.0.0 prereleases (#284)

The addon now requires Storybook 8.2.0 and upwards (was previously 8.0.0), and has a peer dependency on the storybook-package. That package should always be in your project anyway though.


💥 Breaking Change

🚀 Enhancement

🐛 Bug Fix

🏠 Internal

📝 Documentation

🧪 Tests

Authors: 12


v4.2.0 (Thu Nov 28 2024)

🚀 Enhancement

Authors: 1


v4.1.7 (Sun Sep 01 2024)

🐛 Bug Fix

Authors: 1


v4.1.6 (Thu Aug 22 2024)

🐛 Bug Fix

Authors: 2


v4.1.5 (Tue Aug 06 2024)

🐛 Bug Fix

  • Fix type errors due to imports from @storybook/types #198 (@rChaoz)

Authors: 1


v4.1.4 (Tue Jul 09 2024)

🐛 Bug Fix

Authors: 1


v4.1.3 (Thu May 16 2024)

🐛 Bug Fix

  • Fix dependency on @storybook/node-logger and @storybook/client-logger #182 (@ndelangen)

🔩 Dependency Updates

Authors: 2


v4.1.2 (Wed Mar 06 2024)

🐛 Bug Fix

⚠️ Pushed to main

📝 Documentation

Authors: 2


v4.1.1 (Wed Jan 31 2024)

🐛 Bug Fix

  • Fix play function not running in the component scope #169 (@j3rem1e)

⚠️ Pushed to main

Authors: 2


v4.1.0 (Fri Dec 29 2023)

🚀 Enhancement

  • Update versions of peer dependencies to allow latest Vite and Vite Svelte plugin #159 (@joekrump)

Authors: 1


v4.0.13 (Tue Nov 21 2023)

🐛 Bug Fix

  • Add component description from jsdoc on meta export #158 (@j3rem1e)

Authors: 1


v4.0.12 (Fri Nov 17 2023)

🐛 Bug Fix

Authors: 1


v4.0.11 (Fri Nov 10 2023)

🐛 Bug Fix

Authors: 1


v4.0.10 (Thu Nov 09 2023)

🐛 Bug Fix

📝 Documentation

Authors: 3


v4.0.9 (Sat Sep 23 2023)

🐛 Bug Fix

  • Fix reactivity of args when HMR remount the RenderContext #144 (@j3rem1e)

Authors: 1


v4.0.8 (Thu Sep 21 2023)

🐛 Bug Fix

Authors: 1


v4.0.7 (Sat Sep 16 2023)

🐛 Bug Fix

Authors: 2


v4.0.6 (Fri Sep 15 2023)

🐛 Bug Fix

  • Allow configuration of filename patterns besides *.stories.svelte #140 (@j3rem1e)

Authors: 1


v4.0.5 (Wed Sep 13 2023)

🐛 Bug Fix

Authors: 1


v4.0.4 (Wed Sep 13 2023)

🐛 Bug Fix

Authors: 1


v4.0.3 (Sat Sep 02 2023)

🐛 Bug Fix

Authors: 1


v4.0.2 (Sat Sep 02 2023)

🐛 Bug Fix

  • [Bug] titlePrefix in advanced story specifiers causes the story to crash with "Didn't find 'xyz' in CSF file" #136 (@j3rem1e)

Authors: 1


v4.0.1 (Thu Aug 31 2023)

🐛 Bug Fix

Authors: 1


v4.0.0 (Tue Aug 29 2023)

💥 Breaking Change

Authors: 1


v3.0.10 (Tue Aug 29 2023)

🐛 Bug Fix

  • Fix: typeof Meta in Svelte v3 (Pin Svelte peer dependency to v3) #127 (@JReinhold)

Authors: 1


v3.0.9 (Wed Aug 23 2023)

🐛 Bug Fix

Authors: 1


v3.0.8 (Wed Aug 23 2023)

🐛 Bug Fix

Authors: 1


v3.0.7 (Tue Aug 01 2023)

🐛 Bug Fix

  • Fix missing types by adding back main and types fields #118 (@hobbes7878)

Authors: 1


v3.0.6 (Tue Aug 01 2023)

🐛 Bug Fix

Authors: 1


v3.0.5 (Mon Jul 31 2023)

🐛 Bug Fix

Authors: 1


v3.0.4 (Wed Jul 19 2023)

🐛 Bug Fix

Authors: 1


v3.0.3 (Fri Jun 09 2023)

🐛 Bug Fix

  • types: use WebRenderer type as new Addon_BaseAnnotations template variable #106 (@specialdoom)

Authors: 1


v3.0.2 (Fri Apr 21 2023)

🐛 Bug Fix

  • Fix stories not re-rendering when args change in Controls #99 (@leika)

Authors: 1


v3.0.1 (Wed Apr 12 2023)

🐛 Bug Fix

Authors: 1


v3.0.0 (Mon Apr 03 2023)

💥 Breaking Change

🐛 Bug Fix

Authors: 3


v2.0.11 (Tue Jan 17 2023)

🐛 Bug Fix

  • Make types compatible with TypeScript strict mode #74 (@RSWilli)

Authors: 1


v2.0.10 (Thu Oct 27 2022)

🐛 Bug Fix

Authors: 1


v2.0.9 (Thu Oct 27 2022)

🐛 Bug Fix

Authors: 2


v2.0.8 (Mon Oct 03 2022)

🐛 Bug Fix

Authors: 1


v2.0.7 (Fri Aug 12 2022)

🐛 Bug Fix

Authors: 1


v2.0.6 (Thu Jul 14 2022)

🐛 Bug Fix

Authors: 1


v2.0.5 (Thu Jul 07 2022)

🐛 Bug Fix

Authors: 1


v2.0.4 (Thu May 19 2022)

🐛 Bug Fix

Authors: 1


v2.0.3 (Wed Apr 20 2022)

🐛 Bug Fix

Authors: 1


v2.0.2 (Sun Apr 17 2022)

🐛 Bug Fix

Authors: 1


v2.0.1 (Fri Apr 08 2022)

🐛 Bug Fix

Authors: 1


v2.0.0 (Fri Apr 08 2022)

💥 Breaking Change

Authors: 1


v1.1.2 (Fri Apr 08 2022)

🐛 Bug Fix

Authors: 1


v1.1.1 (Fri Apr 08 2022)

🐛 Bug Fix

Authors: 2


v1.1.0 (Thu Jun 10 2021)

🚀 Enhancement

Authors: 2


v1.0.1 (Wed Jun 09 2021)

🐛 Bug Fix

⚠️ Pushed to main

Authors: 4


v1.0.0 (Sat Mar 06 2021)

💥 Breaking Change

🐛 Bug Fix

⚠️ Pushed to main

Authors: 3