Storybook Vue Slots Addon
The Storybook Vue Slots Addon, currently at version 9.1.5, provides robust support for integrating Vue 3 slots directly into Storybook's Component Story Format (CSF) files. This addon enables developers to define and control slot content, generate code snippets that include slot definitions, and even wrap slot content with other Vue components, enhancing the interactive documentation of complex Vue components. Maintained as a fork by Webkor, its release cadence is closely tied to major Storybook and Vue 3 versions, ensuring compatibility with the latest ecosystems. It differentiates itself by offering granular control over slot behavior through Storybook's built-in controls, making it easier to visualize and test different slot configurations without manual code changes.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'template')
cause Attempting to define a slot with `description`, `template`, or `components` properties when the slot's value is a simple string, not an object, or if the `slots` object itself is malformed.fixEnsure that advanced slot configurations are defined as objects within `parameters.slots`, e.g., `default: { template: '...' }` instead of `default: '...'`. Basic string definitions are only for simple default content. -
Storybook build fails with error related to 'addon-vue-slots' not found or invalid configuration.
cause The addon string 'storybook-vue-slots' is misspelled in `.storybook/main.ts` or the package was not correctly installed as a dev dependency (`pnpm add -D storybook-vue-slots`).fixVerify that `storybook-vue-slots` is correctly listed in your `devDependencies` in `package.json` and that the string in `.storybook/main.ts` `addons` array matches exactly: `"storybook-vue-slots"`. -
Slots are not rendered or controllable in Storybook UI, even after configuration in `main.ts` and story files.
cause This often happens if the `parameters.slots` object is placed incorrectly (e.g., directly under `meta` instead of `parameters`), or if the story's `template` does not use `args.[slotName]` to receive and display the slot content.fixDouble-check that `parameters.slots` is correctly nested (`meta.parameters.slots`) and that your story's `template` explicitly uses `args.[slotName]` (e.g., `{{ args.default }}`) to dynamically display the content. Also, ensure `argTypes` are defined for the slots if you want them controllable in the Storybook UI panels.
Warnings
- gotcha This addon is a fork of an older project, explicitly maintained by Webkor to provide updates and compatibility with newer Storybook versions (specifically v9.x). Be aware of its specific lineage if encountering issues or seeking support for older Storybook versions, as its behavior and maintenance may diverge from the original project.
- breaking The addon has strict peer dependencies on Storybook v9.1.5+ and `@storybook/vue3` v9.1.5+. Using it with older Storybook major versions (e.g., v8.x or v7.x) or mismatched minor versions may lead to unexpected behavior, build failures, or runtime errors.
- gotcha Slot definitions in CSF files must be correctly nested under `parameters.slots` within the `meta` object or individual story objects. Incorrect placement or syntax will result in the addon not being able to interpret and render the slot content.
Install
-
npm install storybook-vue-slots -
yarn add storybook-vue-slots -
pnpm add storybook-vue-slots
Imports
- Addon Configuration
import 'storybook-vue-slots';
// .storybook/main.ts export default { addons: [ // ... other addons "storybook-vue-slots" ] } satisfies StorybookConfig; - Slot Parameters (Basic)
export default meta = { slots: { default: `Default slot content`, }, };export default meta = { parameters: { slots: { default: `Default slot content`, }, }, }; - Slot Parameters (Advanced)
export default meta = { parameters: { slots: { header: `<AppButton>{{ args.header }}</AppButton>`, }, }, };export default meta = { parameters: { slots: { header: { description: "Header slot", template: `<AppButton>{{ args.header }}</AppButton>`, components: { AppButton } }, }, }, };
Quickstart
import type { Meta, StoryObj } from '@storybook/vue3';
import MyComponent from './MyComponent.vue';
// --- First, install the addon ---
// pnpm add -D storybook-vue-slots
// --- Then, configure in .storybook/main.ts (uncomment in your actual file) ---
// export default {
// addons: [
// // ... other addons
// "storybook-vue-slots"
// ]
// } satisfies StorybookConfig;
// --- Example MyComponent.vue ---
// <template>
// <div style="border: 1px solid #ccc; padding: 15px; border-radius: 5px;">
// <header><slot name="header">Default Header</slot></header>
// <main style="margin: 10px 0;"><slot>Default Content</slot></main>
// <footer><slot name="footer">Default Footer</slot></footer>
// </div>
// </template>
// <script setup lang="ts"></script>
const meta: Meta<typeof MyComponent> = {
component: MyComponent,
title: 'Components/MyComponent with Slots',
parameters: {
slots: {
// Basic string content for the default slot
default: 'This is the default slot content set via Storybook',
// Advanced object for a named slot with description and template
header: {
description: 'A slot for header content, controllable via args',
template: `<div style="background-color: #e0f7fa; padding: 8px;">{{ args.header }}</div>`
},
// Another named slot demonstrating advanced options
footer: {
description: 'A slot for footer content, styled and controlled',
template: `<p style="color: #616161; font-size: 0.9em;">{{ args.footer }}</p>`
}
}
},
// Define argTypes to make slot content controllable in Storybook UI
argTypes: {
default: { control: 'text', description: 'Content for the unnamed (default) slot' },
header: { control: 'text', description: 'Customizable content for the header slot' },
footer: { control: 'text', description: 'Customizable content for the footer slot' },
}
};
export default meta;
type Story = StoryObj<typeof MyComponent>;
export const Primary: Story = {
args: {
default: 'Dynamic content for the default slot!',
header: 'Dynamic Header Title',
footer: 'Dynamic Footer Information © 2025'
},
// The component template needs to render the slots using args
template: `
<MyComponent>
<template v-if="args.default" #default>{{ args.default }}</template>
<template v-if="args.header" #header>{{ args.header }}</template>
<template v-if="args.footer" #footer>{{ args.footer }}</template>
</MyComponent>`
};