# Storybook > ReactVueAngularWeb ComponentsMore --- # Storybook Documentation # Source: https://storybook.js.org/docs/addons/addon-knowledge-base # Page: /docs/addons/addon-knowledge-base # Addon knowledge base ReactVueAngularWeb ComponentsMore Once you understand the basics of writing addons, there are a variety of common enhancements to make your addon better. This page details additional information about addon creation. Use it as a quick reference guide when creating your own addons. ## Disable the addon panel It’s possible to disable the addon panel for a particular story. To make that possible, you need to pass the `paramKey` element when you register the panel: /my-addon/manager.js addons.register(ADDON_ID, () => { addons.add(PANEL_ID, { type: types.PANEL, title: 'My Addon', render: () =>
Addon tab content
, paramKey: 'myAddon', // this element }); }); Then when adding a story, you can pass a disabled parameter. CSF 3CSF Next 🧪 Button.stories.ts|tsx Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Meta } from '@storybook/your-framework'; import { Button } from './Button'; const meta = { /* 👇 The title prop is optional. * See https://storybook.js.org/docs/configure/#configure-story-loading * to learn how to generate automatic titles */ title: 'Button', component: Button, parameters: { myAddon: { disable: true }, // Disables the addon }, } satisfies Meta; export default meta; ## Style your addon Storybook uses [Emotion](https://emotion.sh/docs/introduction) for styling. Alongside with a theme that you can customize! We recommend using Emotion to style your addon’s UI components. That allows you to use the active Storybook theme to deliver a seamless developer experience. If you don’t want to use Emotion, you can use inline styles or another css-in-js lib. You can receive the theme as a prop by using Emotion's `withTheme` HOC. [Read more about theming](../configure/user-interface/theming). ## Storybook components Addon authors can develop their UIs using any React library. But we recommend using Storybook’s UI components in `storybook/internal/components` to build addons faster. When you use Storybook components, you get: * Battle-tested off-the-shelf components * Storybook native look and feel * Built-in support for Storybook theming Use the components listed below with your next addon. Component| Source| Story ---|---|--- Action Bar| [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/ActionBar/ActionBar.tsx)| [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-actionbar--single-item) Addon Panel| [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/addon-panel/addon-panel.tsx)| N/A Badge| [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/Badge/Badge.tsx)| [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-badge--all-badges) Button| [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/Button/Button.tsx)| [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-button--all-buttons) Form| [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/form/index.tsx)| [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-form-button--sizes) Loader| [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/Loader/Loader.tsx)| [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-loader--progress-bar) PlaceHolder| [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/placeholder/placeholder.tsx)| [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-placeholder--single-child) Scroll Area| [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/ScrollArea/ScrollArea.tsx)| [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-scrollarea--vertical) Space| [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/spaced/Spaced.tsx)| [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-spaced--row) Syntax Highlighter| [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/syntaxhighlighter/syntaxhighlighter.tsx)| [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-syntaxhighlighter--bash) Tabs| [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/tabs/tabs.tsx)| [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-tabs--stateful-static) ToolBar| [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/bar/bar.tsx)| N/A ToolTip| [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/tooltip/Tooltip.tsx)| [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-tooltip-tooltip--basic-default) Zoom| [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/Zoom/Zoom.tsx)| [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-zoom--element-actual-size) Complementing the components, also included is a set of UI primitives. Use the content listed below as a reference for styling your addon. Component| Source| Story ---|---|--- Color Palette (see note below)| [See implementation](https://github.com/storybookjs/storybook/blob/next/code/addons/docs/src/blocks/components/ColorPalette.tsx)| [See story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-colorpalette--page) Icon| [See implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/icon/icon.tsx)| [See story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-icon--labels) Typography| [See implementation](https://github.com/storybookjs/storybook/tree/next/code/core/src/components/components/typography)| [See story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-typography--all) ℹ️ The color palette implemented by `@storybook/addon-docs/blocks` is a high-level abstraction of the [`storybook/theming`](https://github.com/storybookjs/storybook/tree/next/code/core/src/theming) module. ## Build system When you're developing your addon as a package, you can’t use `npm link` to add it to your project. List your addon as a local dependency into your package.json: package.json { "dependencies": { "@storybook/addon-controls": "file:///home/username/myrepo" } } ℹ️ Run either `yarn` or `npm install` to install the addon. ## Hot module replacement While developing your addon, you can configure HMR (hot module replacement) to reflect the changes made. ## Standalone Storybook addons If you're developing a standalone addon, add a new script to `package.json` with the following: package.json { "scripts": { "start": "npm run build -- --watch" } } ### Local Storybook addons If you're developing a local Storybook addon built on top of an existing Storybook installation, HMR (hot module replacement) is available out of the box. ## Composing addons in presets If you're working on a preset that loads third-party addons, which you don't have control over, and you need access to certain features (e.g., decorators) or provide additional configurations. In that case, you'll need to update your preset to the following to allow you to load and configure the other addons: my-preset/index.js function managerEntries(entry = []) { return [...entry, import.meta.resolve('my-other-addon/manager')]; } const previewAnnotations = (entry = [], options) => { return [...entry, import.meta.resolve('my-other-addon/preview')]; }; export default { managerEntries, previewAnnotations, }; If you have control over the addons you want to customize. In that case, you can update your preset and implement a custom function to load any additional presets and provide the necessary configuration. Was this page useful? 👍👎 [✍️ Edit on Github](https://github.com/storybookjs/storybook/tree/next/docs/addons/addon-knowledge-base.mdx) --- # Storybook Documentation # Source: https://storybook.js.org/docs/addons/addon-migration-guide # Page: /docs/addons/addon-migration-guide # Addon migration guide for Storybook 10.0 ReactVueAngularWeb ComponentsMore We sincerely appreciate the dedication and effort addon creators put into keeping the Storybook ecosystem vibrant and up-to-date. As Storybook evolves to version 10.0, bringing new features and improvements, this guide is here to assist you in migrating your addons from 9.x to 10.0. If you need to migrate your addon from an earlier version of Storybook, please first refer to the [Addon migration guide for Storybook 9.0](../../../docs/9/addons/addon-migration-guide). ℹ️ We also have a general [Storybook migration guide](../releases/migration-guide) that covers updates to your Storybook instance rather than your addon code. ## Dependency updates You will need to update your Storybook dependencies. Peer dependencies must point to `^10.0.0` to ensure broad compatibility for your end users. Development dependencies can be set to `^10.0.0`, or to `next` if you want to try the latest prerelease all year round. package.json { "devDependencies": { "@storybook/addon-docs": "next", "@storybook/react-vite": "next", "storybook": "next" }, "peerDependencies": { "storybook": "^10.0.0" } } If you still have `@storybook/addon-essentials`, `@storybook/addon-interactions`, `@storybook/addon-links`, or `@storybook/blocks` in your dependencies, you will need to remove them. These packages are empty since Storybook 9 and will no longer be published going forward. ### Supporting earlier versions If your addon supports multiple major versions of Storybook, you can specify a wider version range in your peer dependencies: package.json { "name": "your-storybook-addon", "peerDependencies": { "storybook": "^9.0.0 || ^10.0.0" }, "devDependencies": { "storybook": ">=10.0.0-0 <11.0.0-0" // For local development } } However, we recommend releasing a new major version of your addon alongside new major versions of Storybook. This practice: 1. Makes it easier to maintain your code 2. Allows you to take advantage of new features and improvements 3. Provides a clearer upgrade path for your users ## Key changes for addons Here are the changes in version 10.0 that impact addon development. ### ESM-only builds Storybook 10 requires all addons to be built as ESM-only. This change simplifies the build process and reduces maintenance overhead. You'll need to make many changes to `tsup.config.ts`, so it can be easier to copy the reference file in the [`addon-kit` repository](https://github.com/storybookjs/addon-kit/blob/main/tsup.config.ts). This update brings the following changes: * The Node target moves from Node 20.0 to Node 20.19 * You no longer need to build CJS files * You no longer need to pass `globalManagerPackages` and `globalPreviewPackages` * The `bundler` config in `package.json` no longer needs to be manually typed * We recommend you stop using `exportEntries` and switch exported entries to `previewEntries` and `managerEntries` instead based on where they are consumed by your users tsup.config.ts - import { readFile } from "node:fs/promises"; import { defineConfig, type Options } from "tsup"; - import { globalPackages as globalManagerPackages } from "storybook/internal/manager/globals"; - import { globalPackages as globalPreviewPackages } from "storybook/internal/preview/globals"; - const NODE_TARGET: Options["target"] = "node20"; + const NODE_TARGET = "node20.19"; // Minimum Node version supported by Storybook 10 - type BundlerConfig = { - bundler?: { - exportEntries?: string[]; - nodeEntries?: string[]; - managerEntries?: string[]; - previewEntries?: string[]; - }; - }; export default defineConfig(async (options) => { // reading the three types of entries from package.json, which has the following structure: // { // ... // "bundler": { - // "exportEntries": ["./src/index.ts"], // "managerEntries": ["./src/manager.ts"], - // "previewEntries": ["./src/preview.ts"], + // "previewEntries": ["./src/preview.ts", "./src/index.ts"], // "nodeEntries": ["./src/preset.ts"] // } // } - const packageJson = (await readFile("./package.json", "utf8").then( - JSON.parse, - )) as BundlerConfig; + const packageJson = ( + await import("./package.json", { with: { type: "json" } }) + ).default; + const { bundler: { - exportEntries = [], managerEntries = [], previewEntries = [], nodeEntries = [], - } = {}, + }, } = packageJson; const commonConfig: Options = { - splitting: false, + splitting: true, + format: ["esm"], - minify: !options.watch, treeshake: true, - sourcemap: true, // keep this line commented until https://github.com/egoist/tsup/issues/1270 is resolved // clean: options.watch ? false : true, clean: false, + // The following packages are provided by Storybook and should always be externalized + // Meaning they shouldn't be bundled with the addon, and they shouldn't be regular dependencies either + external: ["react", "react-dom", "@storybook/icons"], }; const configs: Options[] = []; - - // export entries are entries meant to be manually imported by the user - // they are not meant to be loaded by the manager or preview - // they'll be usable in both node and browser environments, depending on which features and modules they depend on - if (exportEntries.length) { - configs.push({ - ...commonConfig, - entry: exportEntries, - dts: { - resolve: true, - }, - format: ["esm", "cjs"], - platform: "neutral", - target: NODE_TARGET, - external: [...globalManagerPackages, ...globalPreviewPackages], - }); - } // manager entries are entries meant to be loaded into the manager UI // they'll have manager-specific packages externalized and they won't be usable in node // they won't have types generated for them as they're usually loaded automatically by Storybook if (managerEntries.length) { configs.push({ ...commonConfig, entry: managerEntries, - format: ["esm"], platform: "browser", - target: BROWSER_TARGETS, + target: "esnext", // we can use esnext for manager entries since Storybook will bundle the addon's manager entries again anyway - external: globalManagerPackages, }); } // preview entries are entries meant to be loaded into the preview iframe // they'll have preview-specific packages externalized and they won't be usable in node // they'll have types generated for them so they can be imported when setting up Portable Stories if (previewEntries.length) { configs.push({ ...commonConfig, entry: previewEntries, - dts: { - resolve: true, - }, - format: ["esm", "cjs"], platform: "browser", - target: BROWSER_TARGETS, + target: "esnext", // we can use esnext for preview entries since Storybook will bundle the addon's preview entries again anyway - external: globalPreviewPackages, + dts: true, }); } // node entries are entries meant to be used in node-only // this is useful for presets, which are loaded by Storybook when setting up configurations // they won't have types generated for them as they're usually loaded automatically by Storybook if (nodeEntries.length) { configs.push({ ...commonConfig, entry: nodeEntries, - format: ["cjs"], platform: "node", target: NODE_TARGET, }); Next, update the `exports` field in your `package.json` to remove mentions of CJS files. package.json "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.js", - "require": "./dist/index.cjs" + "default": "./dist/index.js" }, "./preview": { - "types": "./dist/index.d.ts", - "import": "./dist/preview.js", - "require": "./dist/preview.cjs" + "types": "./dist/preview.d.ts", + "default": "./dist/preview.js" }, - "./preset": "./dist/preset.cjs", + "./preset": "./dist/preset.js", "./manager": "./dist/manager.js", "./package.json": "./package.json" }, Update `tsconfig.json`. tsconfig.json { "compilerOptions": { // … + "moduleResolution": "bundler", // … - "module": "commonjs", + "module": "preserve", // … - "target": "ES2020", + "target": "esnext", // … - "lib": ["es2020", "dom", "dom.iterable"], + "lib": ["esnext", "dom", "dom.iterable"], // … - "rootDir": "./src", + "rootDir": ".", }, - "include": ["src/**/*"] + "include": ["src/**/*", "tsup.config.ts"] } Finally, change the `preset.js` file at the top-level of your addon to be ESM. This file used to be CJS because the Storybook Node app only supported CJS. preset.js -// this file is slightly misleading. It needs to be CJS, and thus in this "type": "module" package it should be named preset.cjs -// but Storybook won't pick that filename up so we have to name it preset.js instead - -module.exports = require('./dist/preset.cjs'); +export * from './dist/preset.js'; ### Local addon loading Because addons are now ESM-only, you must change how you load your own addon in your development Storybook instance. Imports and exports must now follow ESM syntax, and relative paths must use `import.meta.resolve`. Remove `.storybook/local-preset.cjs` and create `.storybook/local-preset.ts` with the following content: .storybook/local-preset.ts import { fileURLToPath } from "node:url"; export function previewAnnotations(entry = []) { return [...entry, fileURLToPath(import.meta.resolve("../dist/preview.js"))]; } export function managerEntries(entry = []) { return [...entry, fileURLToPath(import.meta.resolve("../dist/manager.js"))]; } export * from "../dist/preset.js"; Next, update your `main.ts` to reference the new preset file: .storybook/main.ts - addons: ["@storybook/addon-docs", "./local-preset.cjs"], + addons: ["@storybook/addon-docs", import.meta.resolve("./local-preset.ts")], ## Optional changes The following changes are not strictly required yet, but we recommend making them to improve your users' experience. ### CSF Factories support To support CSF Factories annotations in your addon, you will need to update your `src/index.ts` file to use the new `definePreviewAddon`. This feature will be part of [CSF Next](../api/csf/csf-next). This change is highly recommended, as it will help your own users reap the benefits of CSF Factories. With CSF Factories, users can chain their preview configuration and benefit from better typing and more flexibility. Addons must export annotations to be compatible with this new syntax. CSF Factories will be the default way to write stories in Storybook 11. src/index.ts - // make it work with --isolatedModules - export default {}; + import { definePreviewAddon } from "storybook/internal/csf"; + import addonAnnotations from "./preview"; + + export default () => definePreviewAddon(addonAnnotations); ### Removal of exportEntries The `exportEntries` property in `package.json`'s `bundler` was used to produce the `index.js` build output from `src/index.ts`. It was compatible with Node.js, rather than strictly with browsers. This build configuration could cause subtle bugs when addon authors exported code in `index.js` for use in the Storybook preview or manager. In the Storybook 10 [addon-kit](https://github.com/storybookjs/addon-kit), we removed `exportEntries` from the `bundler` config, and we moved `src/index.ts` to be part of `previewEntries` instead. This way, any code exported from `src/index.ts` is bundled for browsers and usable with CSF Next. If you need to export additional code to run in the preview (such as optional decorators), you can add them to `src/index.ts`. If you need to export code for the manager (such as a `renderLabel` function for the sidebar), you can create a new `src/manager-helpers.ts` file and add it to `managerEntries`, like so: package.json "exports": { ".": { "types": "./dist/index.d.ts", "default": "./dist/index.js" }, "./preview": { "types": "./dist/preview.d.ts", "default": "./dist/preview.js" }, "./preset": "./dist/preset.js", "./manager": "./dist/manager.js", + "./manager-helpers": "./dist/manager-helpers.js", "./package.json": "./package.json" }, "bundler": { "managerEntries": [ + "src/manager-helpers.ts", "src/manager.tsx" ] } ### Build file cleanup We recommend removing your old build files as you build. This will avoid your `dist` folder growing with expired JS chunks. You may add the following to your `package.json` scripts: package.json { "scripts": { + "prebuild": "node -e \"fs.rmSync('./dist', { recursive: true, force: true })\"", } } ### Package keyword changes We've updated default keywords for addons in the Storybook `addon-kit` template. package.json "keywords": [ - "storybook-addons", + "storybook-addon", ], ## 10.0.0 full migration guide For a full list of changes, please visit the [Migration.md](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#from-version-9x-to-1000) file ## Migration example For a complete example of an addon updated to support Storybook 10.0, refer to the [Addon Kit migration PR](https://github.com/storybookjs/addon-kit/pull/82). Once merged, it will demonstrate all the necessary and recommended changes for Storybook 10. ## Releasing To support Storybook 10.0, we encourage you to release a new major version of your addon. For experimental features or testing, use the `next` tag. This allows you to gather feedback before releasing a stable version. ## Support If you're having issues with your addon after following this guide, please open a [new discussion](https://github.com/storybookjs/storybook/discussions/new?category=migrations) in our GitHub repository or come talk to us in our [dedicated addon developer channel, `#addons`](https://discord.gg/KKXFQy9sFc) on Discord. Was this page useful? 👍👎 [✍️ Edit on Github](https://github.com/storybookjs/storybook/tree/next/docs/addons/addon-migration-guide.mdx) --- # Storybook Documentation # Source: https://storybook.js.org/docs/addons/addon-types # Page: /docs/addons/addon-types # Types of addons ReactVueAngularWeb ComponentsMore Each Storybook addon is classified into two general categories, UI-based or Presets. Each type of addons feature is documented here. Use this as a reference when creating your addon. ## UI-based addons UI-based addons allow you to customize Storybook's UI with the following elements. ### Panels Panel addons allow you to add your own UI in Storybook's addon panel. This is the most common type of addon in the ecosystem. For example, the official [`@storybook/addon-a11y`](https://github.com/storybookjs/storybook/tree/next/code/addons/a11y) uses this pattern. ![Storybook panel](/docs-assets/10.1/addons/storybook-panel.png) Use this boilerplate code to add a new `Panel` to Storybook's UI: addon-panel/manager.js import React from 'react'; import { AddonPanel } from 'storybook/internal/components'; import { useGlobals, addons, types } from 'storybook/manager-api'; addons.register('my/panel', () => { addons.add('my-panel-addon/panel', { title: 'Example Storybook panel', //👇 Sets the type of UI element in Storybook type: types.PANEL, render: ({ active }) => (

I'm a panel addon in Storybook

), }); }); ### Toolbars Toolbar addons allow you to add your own custom tools in Storybook's Toolbar. For example, the official [`@storybook/addon-themes`](https://storybook.js.org/addons/@storybook/addon-themes) uses this pattern. ![Storybook toolbar addon](/docs-assets/10.1/addons/storybook-toolbar.png) Use this boilerplate code to add a new `button` to Storybook's Toolbar: addon-toolbar/manager.js import React from 'react'; import { addons, types } from 'storybook/manager-api'; import { ToggleButton } from 'storybook/internal/components'; import { OutlineIcon } from '@storybook/icons'; addons.register('my-addon', () => { addons.add('my-addon/toolbar', { title: 'Example Storybook toolbar', //👇 Sets the type of UI element in Storybook type: types.TOOL, //👇 Shows the Toolbar UI element if the story canvas is being viewed match: ({ tabId, viewMode }) => !tabId && viewMode === 'story', render: ({ active }) => ( ), }); }); ℹ️ The `match` property allows you to conditionally render your toolbar addon, [based on the current view](./writing-addons#conditionally-render-the-addon). The `icon` element used in the example loads the icons from the `storybook/internal/components` module. See [here](../faq#what-icons-are-available-for-my-toolbar-or-my-addon) for the list of available icons that you can use. ### Tabs Tab addons allow you to create your own custom tabs in Storybook. ![Storybook tab addon](/docs-assets/10.1/addons/storybook-tab.png) Use this boilerplate code to add a new `Tab` to Storybook's UI: addon-tab/manager.js import React from 'react'; import { addons, types } from 'storybook/manager-api'; addons.register('my-addon', () => { addons.add('my-addon/tab', { type: types.TAB, title: 'Example Storybook tab', render: () => (

I'm a tabbed addon in Storybook

), }); }); ℹ️ Learn how to write your own addon that includes these UI elements [here](./writing-addons). ## Preset addons Storybook preset addons are grouped collections of `babel`, `webpack`, and `addons` configurations to integrate Storybook and other technologies. For example the official [preset-create-react-app](https://github.com/storybookjs/presets/tree/master/packages/preset-create-react-app). Use this boilerplate code while writing your own preset addon. .storybook/my-preset.js export default { managerWebpack: async (config, options) => { // Update config here return config; }, webpackFinal: async (config, options) => { return config; }, babel: async (config, options) => { return config; }, }; **Learn more about the Storybook addon ecosystem** * Types of addons for other types of addons * [Writing addons](./writing-addons) for the basics of addon development * [Presets](./writing-presets) for preset development * [Integration catalog](./integration-catalog) for requirements and available recipes * [API reference](./addons-api) to learn about the available APIs Was this page useful? 👍👎 [✍️ Edit on Github](https://github.com/storybookjs/storybook/tree/next/docs/addons/addon-types.mdx) --- # Storybook Documentation # Source: https://storybook.js.org/docs/addons/addons-api # Page: /docs/addons/addons-api # Addon API ReactVueAngularWeb ComponentsMore Storybook's API allows developers to interact programmatically with Storybook. With the API, developers can build and deploy custom addons and other tools that enhance Storybook's functionality. ## Core Addon API Our API is exposed via two distinct packages, each one with a different purpose: * `storybook/manager-api` used to interact with the Storybook manager UI or access the Storybook API. * `storybook/preview-api` used to control and configure the addon's behavior. my-addon/src/manager.js|ts import { addons } from 'storybook/preview-api'; import { useStorybookApi } from 'storybook/manager-api'; ### addons.add() The `add` method allows you to register the type of UI component associated with the addon (e.g., panels, toolbars, tabs). For a minimum viable Storybook addon, you should provide the following arguments: * `type`: The type of UI component to register. * `title`: The title to feature in the Addon Panel. * `render`: The function that renders the addon's UI component. my-addon/src/manager.js|ts import React from 'react'; import { addons, types } from 'storybook/manager-api'; import { AddonPanel } from 'storybook/internal/components'; const ADDON_ID = 'myaddon'; const PANEL_ID = `${ADDON_ID}/panel`; addons.register(ADDON_ID, (api) => { addons.add(PANEL_ID, { type: types.PANEL, title: 'My Addon', render: ({ active }) => (
Storybook addon panel
), }); }); ℹ️ The render function is called with `active`. The `active` value will be true when the panel is focused on the UI. ### addons.register() Serves as the entry point for all addons. It allows you to register an addon and access the Storybook API. For example: my-addon/src/manager.js|ts import { addons } from 'storybook/preview-api'; // Register the addon with a unique name. addons.register('my-organisation/my-addon', (api) => {}); Now you'll get an instance to our StorybookAPI. See the api docs for Storybook API regarding using that. ### addons.getChannel() Get an instance to the channel to communicate with the manager and the preview. You can find this in both the addon register code and your addon’s wrapper component (where used inside a story). It has a NodeJS [EventEmitter](https://nodejs.org/api/events.html) compatible API. So, you can use it to emit events and listen to events. my-addon/src/manager.js|ts import React, { useCallback } from 'react'; import { OutlineIcon } from '@storybook/icons'; import { useGlobals } from 'storybook/manager-api'; import { addons } from 'storybook/preview-api'; import { ToggleButton } from 'storybook/internal/components'; import { FORCE_RE_RENDER } from 'storybook/internal/core-events'; const ExampleToolbar = () => { const [globals, updateGlobals] = useGlobals(); const isActive = globals['my-param-key'] || false; // Function that will update the global value and trigger a UI refresh. const refreshAndUpdateGlobal = () => { updateGlobals({ ['my-param-key']: !isActive, }), // Invokes Storybook's addon API method (with the FORCE_RE_RENDER) event to trigger a UI refresh addons.getChannel().emit(FORCE_RE_RENDER); }; const toggleToolbarAddon = useCallback(() => refreshAndUpdateGlobal(), [isActive]); return ( ); }; ### makeDecorator Use the `makeDecorator` API to create decorators in the style of the official addons. Like so: my-addon/src/decorator.js|ts import { makeDecorator } from 'storybook/preview-api'; export const withAddonDecorator = makeDecorator({ name: 'withSomething', parameterName: 'CustomParameter', skipIfNoParametersOrOptions: true, wrapper: (getStory, context, { parameters }) => { /* * Write your custom logic here based on the parameters passed in Storybook's stories. * Although not advised, you can also alter the story output based on the parameters. */ return getStory(context); }, }); ℹ️ If the story's parameters include `{ exampleParameter: { disable: true } }` (where `exampleParameter` is the `parameterName` of your addon), your decorator will not be called. The `makeDecorator` API requires the following arguments: * `name`: Unique name to identify the custom addon decorator. * `parameterName`: Sets a unique parameter to be consumed by the addon. * `skipIfNoParametersOrOptions`: (Optional) Doesn't run the decorator if the user hasn't options either via [decorators](../writing-stories/decorators) or [parameters](../writing-stories/parameters). * `wrapper`: your decorator function. Takes the `getStory`, `context`, and both the `options` and `parameters` (as defined in `skipIfNoParametersOrOptions` above). * * * ## Storybook API Storybook's API allows you to access different functionalities of Storybook UI. ### api.selectStory() The `selectStory` API method allows you to select a single story. It accepts the following two parameters; story kind name and an optional story name. For example: CSF 3CSF Next 🧪 Button.stories.ts|tsx Typescript import * as React from 'react'; // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc. import type { Meta, StoryObj } from '@storybook/your-framework'; import { Button } from './Button'; const meta = { /* 👇 The title prop is optional. * See https://storybook.js.org/docs/configure/#configure-story-loading * to learn how to generate automatic titles */ title: 'Button', component: Button, //👇 Creates specific parameters for the story parameters: { myAddon: { data: 'This data is passed to the addon', }, }, } satisfies Meta; export default meta; type Story = StoryObj; /* *👇 Render functions are a framework specific feature to allow you control on how the component renders. * See https://storybook.js.org/docs/api/csf * to learn how to use render functions. */ export const Basic: Story = { render: () => , }; This is how you can select the above story: my-addon/src/manager.js|ts addons.register('my-organisation/my-addon', (api) => { api.selectStory('Button', 'Default'); }); ### api.selectInCurrentKind() Similar to the `selectStory` API method, but it only accepts the story as the only parameter. my-addon/src/manager.js|ts addons.register('my-organisation/my-addon', (api) => { api.selectInCurrentKind('Default'); }); ### api.setQueryParams() This method allows you to set query string parameters. You can use that as temporary storage for addons. Here's how you define query params: my-addon/src/manager.js|ts addons.register('my-organisation/my-addon', (api) => { api.setQueryParams({ exampleParameter: 'Sets the example parameter value', anotherParameter: 'Sets the another parameter value', }); }); Additionally, if you need to remove a query parameter, set it as `null` instead of removing them from the addon. For example: my-addon/src/manager.js|ts addons.register('my-organisation/my-addon', (api) => { api.setQueryParams({ exampleParameter: null, }); }); ### api.getQueryParam() Allows retrieval of a query parameter enabled via the `setQueryParams` API method. For example: my-addon/src/manager.js|ts addons.register('my-organisation/my-addon', (api) => { api.getQueryParam('exampleParameter'); }); ### api.getUrlState(overrideParams) This method allows you to get the application URL state, including any overridden or custom parameter values. For example: my-addon/src/manager.js|ts addons.register('my-organisation/my-addon', (api) => { const href = api.getUrlState({ selectedKind: 'kind', selectedStory: 'story', }).url; }); ### api.on(eventName, fn) This method allows you to register a handler function called whenever the user navigates between stories. my-addon/src/manager.js|ts addons.register('my-organisation/my-addon', (api) => { // Logs the event data to the browser console whenever the event is emitted. api.on('custom-addon-event', (eventData) => console.log(eventData)); }); ### addons.setConfig(config) This method allows you to override the default Storybook UI configuration (e.g., set up a [theme](../configure/user-interface/theming) or hide UI elements): .storybook/manager.ts Typescript import { addons, type State } from 'storybook/manager-api'; addons.setConfig({ navSize: 300, bottomPanelHeight: 300, rightPanelWidth: 300, panelPosition: 'bottom', enableShortcuts: true, showToolbar: true, theme: undefined, selectedPanel: undefined, initialActive: 'sidebar', layoutCustomisations: { showSidebar(state: State, defaultValue: boolean) { return state.storyId === 'landing' ? false : defaultValue; }, showToolbar(state: State, defaultValue: boolean) { return state.viewMode === 'docs' ? false : defaultValue; }, }, sidebar: { showRoots: false, collapsedRoots: ['other'], }, toolbar: { title: { hidden: false }, zoom: { hidden: false }, eject: { hidden: false }, copy: { hidden: false }, fullscreen: { hidden: false }, }, }); The following table details how to use the API values: Name| Type| Description| Example Value ---|---|---|--- **navSize**| Number (pixels)| The size of the sidebar that shows a list of stories| `300` **bottomPanelHeight**| Number (pixels)| The size of the addon panel when in the bottom position| `200` **rightPanelWidth**| Number (pixels)| The size of the addon panel when in the right position| `200` **panelPosition**| String| Where to show the addon panel| `'bottom'` or `'right'` **enableShortcuts**| Boolean| Enable/disable shortcuts| `true` **showToolbar**| Boolean| Show/hide toolbar| `true` **theme**| Object| Storybook Theme, see next section| `undefined` **selectedPanel**| String| Id to select an addon panel| `storybook/actions/panel` **initialActive**| String| Select the default active tab on Mobile| `sidebar` or `canvas` or `addons` **sidebar**| Object| Sidebar options, see below| `{ showRoots: false }` **toolbar**| Object| Modify the tools in the toolbar using the addon id| `{ fullscreen: { hidden: false } }` The following options are configurable under the `sidebar` namespace: Name| Type| Description| Example Value ---|---|---|--- **showRoots**| Boolean| Display the top-level nodes as a "root" in the sidebar| `false` **collapsedRoots**| Array| Set of root node IDs to visually collapse by default| `['misc', 'other']` **renderLabel**| Function| Create a custom label for tree nodes; must return a ReactNode| `(item, api) => {item.name}` The following options are configurable under the `toolbar` namespace: Name| Type| Description| Example Value ---|---|---|--- **[id]**| String| Toggle visibility for a specific toolbar item (e.g. `title`, `zoom`)| `{ hidden: false }` * * * ## Storybook hooks To help streamline addon development and reduce boilerplate code, the API exposes a set of hooks to access Storybook's internals. These hooks are an extension of the `storybook/manager-api` module. ### useStorybookState It allows access to Storybook's internal state. Similar to the `useglobals` hook, we recommend optimizing your addon to rely on [`React.memo`](https://react.dev/reference/react/memo), or the following hooks; [`useMemo`](https://react.dev/reference/react/useMemo), [`useCallback`](https://react.dev/reference/react/useCallback) to prevent a high volume of re-render cycles. my-addon/src/manager.js|ts import React from 'react'; import { AddonPanel } from 'storybook/internal/components'; import { useStorybookState } from 'storybook/manager-api'; export const Panel = () => { const state = useStorybookState(); return ( {state.viewMode !== 'docs' ? (

Do something with the documentation

) : (

Show the panel when viewing the story

)}
); }; ### useStorybookApi The `useStorybookApi` hook is a convenient helper to allow you full access to the Storybook API methods. my-addon/manager.js|ts import React, { useEffect, useCallback } from 'react'; import { useGlobals, useStorybookApi } from 'storybook/manager-api'; import { ToggleButton } from 'storybook/internal/components'; import { ChevronDownIcon } from '@storybook/icons'; export const Panel = () => { const [globals, updateGlobals] = useGlobals(); const api = useStorybookApi(); const isActive = [true, 'true'].includes(globals[PARAM_KEY]); const toggleMyTool = useCallback(() => { updateGlobals({ [PARAM_KEY]: !isActive, }); }, [isActive]); useEffect(() => { api.setAddonShortcut('custom-toolbar-addon', { label: 'Enable my addon', defaultShortcut: ['G'], actionName: 'Toggle', showInMenu: false, action: toggleMyTool, }); }, [api]); return ( ); }; ### useChannel Allows setting subscriptions to events and getting the emitter to emit custom events to the channel. The messages can be listened to on both the iframe and the manager. my-addon/manager.js|ts import React from 'react'; import { useChannel } from 'storybook/manager-api'; import { AddonPanel, Button } from 'storybook/internal/components'; import { STORY_CHANGED } from 'storybook/internal/core-events'; export const Panel = () => { // Creates a Storybook API channel and subscribes to the STORY_CHANGED event const emit = useChannel({ STORY_CHANGED: (...args) => console.log(...args), }); return ( ); }; ### useAddonState The `useAddonState` is a useful hook for addons that require data persistence, either due to Storybook's UI lifecycle or for more complex addons involving multiple types (e.g., toolbars, panels). my-addon/manager.js|ts import React from 'react'; import { useAddonState } from 'storybook/manager-api'; import { AddonPanel, Button, ToggleButton } from 'storybook/internal/components'; import { LightningIcon } from '@storybook/icons'; export const Panel = () => { const [state, setState] = useAddonState('addon-unique-identifier', 'initial state'); return ( ); }; export const Tool = () => { const [state, setState] = useAddonState('addon-unique-identifier', 'initial state'); return ( setState('Example')} > ); }; ### useParameter The `useParameter` retrieves the current story's parameters. If the parameter's value is not defined, it will automatically default to the second value defined. my-addon/manager.js|ts import React from 'react'; import { AddonPanel } from 'storybook/internal/components'; import { useParameter } from 'storybook/manager-api'; export const Panel = () => { // Connects to Storybook's API and retrieves the value of the custom parameter for the current story const value = useParameter('custom-parameter', 'initial value'); return ( {value === 'initial value' ? (

The story doesn't contain custom parameters. Defaulting to the initial value.

) : (

You've set {value} as the parameter.

)}
); }; ### useGlobals Extremely useful hook for addons that rely on Storybook [Globals](../essentials/toolbars-and-globals). It allows you to obtain and update `global` values. We also recommend optimizing your addon to rely on [`React.memo`](https://react.dev/reference/react/memo), or the following hooks; [`useMemo`](https://react.dev/reference/react/useMemo), [`useCallback`](https://react.dev/reference/react/useCallback) to prevent a high volume of re-render cycles. my-addon/manager.js|ts import React from 'react'; import { AddonPanel, Button } from 'storybook/internal/components'; import { useGlobals } from 'storybook/manager-api'; export const Panel = () => { const [globals, updateGlobals] = useGlobals(); const isActive = globals['my-param-key'] || false; // 👈 Sets visibility based on the global value. return ( ); }; ### useArgs Hook that allows you to retrieve or update a story's [`args`](../writing-stories/args). my-addon/src/manager.js|ts import { useArgs } from 'storybook/manager-api'; const [args, updateArgs, resetArgs] = useArgs(); // To update one or more args: updateArgs({ key: 'value' }); // To reset one (or more) args: resetArgs((argNames: ['key'])); // To reset all args resetArgs(); **Learn more about the Storybook addon ecosystem** * [Types of addons](./addon-types) for other types of addons * [Writing addons](./writing-addons) for the basics of addon development * [Presets](./writing-presets) for preset development * [Integration catalog](./integration-catalog) for requirements and available recipes * API reference to learn about the available APIs Was this page useful? 👍👎 [✍️ Edit on Github](https://github.com/storybookjs/storybook/tree/next/docs/addons/addons-api.mdx) --- # Storybook Documentation # Source: https://storybook.js.org/docs/addons/configure-addons # Page: /docs/addons/configure-addons # Configure and communicate with an addon ReactVueAngularWeb ComponentsMore The addon API is designed for customization. It offers addon authors different ways to configure and communicate with their users' Storybook. Let's look at what these are and their suggested use cases. ## Preset Presets offload the burden of configuration from the user to the addon. Preset options are global and are accessible from NodeJS. They're ideal for pre-configuring Webpack loaders, Babel plugins, and other library or framework-specific configurations. For example, many libraries require that the app be wrapped by a `Provider` which _provides_ data to components down the tree. Presets can describe behavior like adding wrappers automatically, without users having to do any manual configuration. If a user installs an addon that has Presets, the addon can instruct Storybook to wrap all stories in `Provider`. This allows folks to start using your library with Storybook, with just 1 line of config! For more on presets, see: [Write a preset addon](./writing-presets) The mechanism for wrapping each story is referred to as a Storybook [decorator](../writing-stories/decorators). They allow you to augment stories with extra rendering functionality or by providing data. ## Parameters Parameters are available in the browser and are great for configuring addon behavior globally, at the component level, or at the story level. For example, the [Pseudo States addon](https://storybook.js.org/addons/storybook-addon-pseudo-states) uses parameters to enable the various pseudo-states. Users can provide global defaults and then override them at the story level. Use the [`useParameter`](./addons-api#useparameter) hook to access the parameter values within your addon. export const Hover = { render: () => , parameters: { pseudo: { hover: true } }, }; ## Channels Channels enable two-way communication between the manager and the preview pane, using a NodeJS [EventEmitter](https://nodejs.org/api/events.html) compatible API. Your addons can plug into specific channels and respond to these events. For example, [Actions](https://storybook.js.org/docs/essentials/actions) captures user events and displays their data in a panel. Use the [`useChannel`](./addons-api#usechannel) hook to access the channel data within your addon. For a complete example, check out [storybookjs/addon-kit/withRoundTrip.ts](https://github.com/storybookjs/addon-kit/blob/main/src/withRoundTrip.ts) Was this page useful? 👍👎 [✍️ Edit on Github](https://github.com/storybookjs/storybook/tree/next/docs/addons/configure-addons.mdx) --- # Storybook Documentation # Source: https://storybook.js.org/docs/addons/install-addons # Page: /docs/addons/install-addons # Install addons ReactVueAngularWeb ComponentsMore Storybook has [hundreds of reusable addons](https://storybook.js.org/integrations) packaged as NPM modules. Let's walk through how to extend Storybook by installing and registering addons. ## Automatic installation Storybook includes a [`storybook add`](../api/cli-options#add) command to automate the setup of addons. Several community-led addons can be added using this command, except for preset addons. We encourage you to read the addon's documentation to learn more about its installation process. Run the `storybook add` command using your chosen package manager, and the CLI will update your Storybook configuration to include the addon and install any necessary dependencies. npm npx storybook@latest add @storybook/addon-a11y ⚠️ If you're attempting to install multiple addons at once, it will only install the first addon that was specified. This is a known limitation of the current implementation and will be addressed in a future release. ### Manual installation Storybook addons are always added through the [`addons`](../api/main-config/main-config-addons) configuration array in [`.storybook/main.js|ts`](../configure). The following example shows how to manually add the [Accessibility addon](https://storybook.js.org/addons/@storybook/addon-a11y) to Storybook. Run the following command with your package manager of choice to install the addon. npm npm install @storybook/addon-a11y --save-dev Next, update `.storybook/main.js|ts` to the following: CSF 3CSF Next 🧪 .storybook/main.ts Typescript // Replace your-framework with the framework you are using (e.g., react-vite, vue3-vite, angular, etc.) import type { StorybookConfig } from '@storybook/your-framework'; const config: StorybookConfig = { framework: '@storybook/your-framework', stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], addons: [ // Other Storybook addons '@storybook/addon-a11y', //👈 The a11y addon goes here ], }; export default config; When you run Storybook, the accessibility testing addon will be enabled. ![Storybook addon installed and registered](/docs-assets/10.1/addons/storybook-addon-installed-registered.png) ### Removing addons To remove an addon from Storybook, you can choose to manually uninstall it and remove it from the configuration file (i.e., [`.storybook/main.js|ts`](../configure)) or opt-in to do it automatically via the CLI with the [`remove`](../api/cli-options#remove) command. For example, to remove the [Accessibility addon](https://storybook.js.org/addons/@storybook/addon-a11y) from Storybook with the CLI, run the following command: npm npx storybook@latest remove @storybook/addon-a11y Was this page useful? 👍👎 [✍️ Edit on Github](https://github.com/storybookjs/storybook/tree/next/docs/addons/install-addons.mdx) --- # Storybook Documentation # Source: https://storybook.js.org/docs/addons/integration-catalog # Page: /docs/addons/integration-catalog # Add to the integration catalog ReactVueAngularWeb ComponentsMore Storybook has two types of integrations, addons and recipes, which are listed in the [integration catalog](https://storybook.js.org/integrations/). ## Addons Storybook addons are distributed via npm. The catalog is populated by querying npm's registry for Storybook-specific metadata in `package.json`. Add your addon to the catalog by publishing a npm package that follows these requirements: * `package.json` with [module information](./writing-addons#setup) and addon metadata * `README.md` file with installation and configuration instructions * `/dist` directory containing transpiled ES5 code * `preset.js` file written as an ES5 module at the root level 💡 Get a refresher on how to [write a Storybook addon](./writing-addons). ### Addon metadata We rely on metadata to organize your addon in the catalog. You must add the `storybook-addon` as the first keyword, followed by your addon's category. Additional keywords will be used in search and as tags. Property| Description| Example ---|---|--- `name`| Addon package name| storybook-addon-example `description`| Addon description| Outline all elements with CSS to help with layout placement and alignment `author`| Name of the author| winkerVSbecks `keywords`| List of keywords to describe the addon| `["storybook-addon","style","debug"]` `repository`| Addon repository| `{"type": "git","url": "https://github.com/someone/my-addon" }` Customize your addon's appearance by adding the `storybook` property with the following fields. Property| Description| Example ---|---|--- `displayName`| Display name| Example `icon`| Link to custom icon for the addon (SVG are not supported)| `unsupportedFrameworks`| List of unsupported frameworks| `["vue"]` `supportedFrameworks`| List of supported frameworks| `["react", "angular"]` Use the list below as a reference when filling in the values for both the `supportedFrameworks` and `unsupportedFrameworks` fields. * react * vue * angular * web-components * ember * html * svelte * preact * react-native 💡 Make sure to copy each item **exactly** as listed so that we can properly index your addon in our catalog. package.json { "name": "storybook-addon-example", "version": "1.0.0", "description": "Outline all elements with CSS to help with layout placement and alignment", "repository": { "type": "git", "url": "https://github.com/chromaui/storybook-addon-example" }, "author": "winkerVSbecks", "keywords": ["storybook-addon", "style", "debug", "layout", "css"], "storybook": { "displayName": "Outline", "unsupportedFrameworks": ["vue"], "supportedFrameworks": ["react", "angular"], "icon": "https://yoursite.com/addon-icon.png" } } The `package.json` above appears like below in the catalog. See an example of a production package.json [here](https://github.com/chromaui/storybook-outline/blob/main/package.json). ![Storybook addon in the catalog](/docs-assets/10.1/addons/addon-display.png) #### How long does it take for my addon to show up in the catalog? Once you publish the addon, it will appear in the catalog. There may be a delay between the time you publish your addon and when it's listed in the catalog. If your addon doesn't show up within 24 hours, [open an issue](https://github.com/storybookjs/frontpage/issues). ## Recipes Recipes are a set of instructions to integrate third-party libraries into Storybook in cases where an addon does not exist or the integration requires some manual effort. ### Who owns them? Recipes are written and maintained by the Storybook team. We create recipes based on community popularity, tool maturity, and stability of the integration. Our goal is to ensure that recipes continue to work over time. Not finding the recipe that you want? If it's popular in the community, our docs team will write one. In the mean time, try searching for a solution — it's likely that someone has the same requirements as you do. You can also help us out by writing recipes on your own site which speeds up the research process. ### Request a recipe If you'd like to request a recipe, open a [new discussion](https://github.com/storybookjs/storybook/discussions/new?category=ideas) in our GitHub repo. We'll review your request, and if it's popular, we'll add it to our backlog and prioritize it. **Learn more about the Storybook addon ecosystem** * [Types of addons](./addon-types) for other types of addons * [Writing addons](./writing-addons) for the basics of addon development * [Presets](./writing-presets) for preset development * Integration catalog for requirements and available recipes * [API reference](./addons-api) to learn about the available APIs Was this page useful? 👍👎 [✍️ Edit on Github](https://github.com/storybookjs/storybook/tree/next/docs/addons/integration-catalog.mdx) --- # Storybook Documentation # Source: https://storybook.js.org/docs/addons/writing-addons # Page: /docs/addons/writing-addons # Write an addon ReactVueAngularWeb ComponentsMore Storybook addons are a powerful way to extend Storybook's functionality and customize the development experience. They can be used to add new features, customize the UI, or integrate with third-party tools. ## What are we going to build? This reference guide is to help you develop a mental model for how Storybook addons work by building a simple addon based on the popular [Outline addon](https://storybook.js.org/addons/@storybook/addon-outline/) (which is the historical basis for the built-in [outline feature](../essentials/measure-and-outline#outline)). Throughout this guide, you'll learn how addons are structured, Storybook's APIs, how to test your addon locally, and how to publish it. ![Fully implemented Storybook addon](/docs-assets/10.1/addons/storybook-addon-finished-state.png) ## Addon anatomy There are two main categories of addons, each with its role: * **UI-based** : These addons are responsible for customizing the interface, enabling shortcuts for common tasks, or displaying additional information in the UI. * **Presets** : [These](./writing-presets) are pre-configured settings or configurations that enable developers to quickly set up and customize their environment with a specific set of features, functionality, or technology. ### UI-based addons The addon built in this guide is a UI-based addon, specifically a [toolbar](./addon-types#toolbars) addon, enabling users to draw outlines around each element in the story through a shortcut or click of a button. UI addons can create other types of UI elements, each with its function: [panels](./addon-types#panels) and [tabs](./addon-types#tabs), providing users with various ways to interact with the UI. ToolbarPanelTab src/Tool.tsx import React, { memo, useCallback, useEffect } from 'react'; import { useGlobals, useStorybookApi } from 'storybook/manager-api'; import { ToggleButton } from 'storybook/internal/components'; import { LightningIcon } from '@storybook/icons'; import { ADDON_ID, PARAM_KEY, TOOL_ID } from './constants'; export const Tool = memo(function MyAddonSelector() { const [globals, updateGlobals] = useGlobals(); const api = useStorybookApi(); const isActive = [true, 'true'].includes(globals[PARAM_KEY]); const toggleMyTool = useCallback(() => { updateGlobals({ [PARAM_KEY]: !isActive, }); }, [isActive]); useEffect(() => { api.setAddonShortcut(ADDON_ID, { label: 'Toggle Outline', defaultShortcut: ['alt', 'O'], actionName: 'outline', showInMenu: false, action: toggleMyTool, }); }, [toggleMyTool, api]); return ( ); }); ## Setup To create your first addon, you're going to use the [Addon Kit](https://github.com/storybookjs/addon-kit), a ready-to-use template featuring all the required building blocks, dependencies and configurations to help you get started building your addon. In the Addon Kit repository, click the **Use this template** button to create a new repository based on the Addon Kit's code. Clone the repository you just created and install its dependencies. When the installation process finishes, you will be prompted with questions to configure your addon. Answer them, and when you're ready to start building your addon, run the following command to start Storybook in development mode and develop your addon in watch mode: npm npm run start ℹ️ The Addon Kit uses [Typescript](https://www.typescriptlang.org/) by default. If you want to use JavaScript instead, you can run the `eject-ts` command to convert the project to JavaScript. ### Understanding the build system Addons built in the Storybook ecosystem rely on [tsup](https://tsup.egoist.dev/), a fast, zero-config bundler powered by [esbuild](https://esbuild.github.io/) to transpile your addon's code into modern JavaScript that can run in the browser. Out of the box, the Addon Kit comes with a pre-configured `tsup` configuration file that you can use to customize the build process of your addon. When the build scripts run, it will look for the configuration file and pre-bundle the addon's code based on the configuration provided. Addons can interact with Storybook in various ways. They can define presets to modify the configuration, add behavior to the manager UI, or add behavior to the preview iframe. These different use cases require different bundle outputs because they target different runtimes and environments. Presets are executed in a Node environment. Storybook's manager and preview environments provide certain packages in the global scope, so addons don't need to bundle them or include them as dependencies in their `package.json` file. The `tsup` configuration handles these complexities by default, but you can customize it according to their requirements. For a detailed explanation of the bundling techniques used, please refer to [the README of the addon-kit](https://github.com/storybookjs/addon-kit#bundling), and check out the default `tsup` configuration [here](https://github.com/storybookjs/addon-kit/blob/main/tsup.config.ts). ## Register the addon By default, code for the UI-based addons is located in one of the following files, depending on the type of addon built: **`src/Tool.tsx`** , **`src/Panel.tsx`** , or **`src/Tab.tsx`**. Since we're building a toolbar addon, we can safely remove the `Panel` and `Tab` files and update the remaining file to the following: src/Tool.tsx import React, { memo, useCallback, useEffect } from 'react'; import { useGlobals, useStorybookApi } from 'storybook/manager-api'; import { ToggleButton } from 'storybook/internal/components'; import { LightningIcon } from '@storybook/icons'; import { ADDON_ID, PARAM_KEY, TOOL_ID } from './constants'; export const Tool = memo(function MyAddonSelector() { const [globals, updateGlobals] = useGlobals(); const api = useStorybookApi(); const isActive = [true, 'true'].includes(globals[PARAM_KEY]); const toggleMyTool = useCallback(() => { updateGlobals({ [PARAM_KEY]: !isActive, }); }, [isActive]); useEffect(() => { api.setAddonShortcut(ADDON_ID, { label: 'Toggle Addon [8]', defaultShortcut: ['8'], actionName: 'myaddon', showInMenu: false, action: toggleMyTool, }); }, [toggleMyTool, api]); return ( ); }); Going through the code blocks in sequence: src/Tool.tsx import { useGlobals, useStorybookApi } from 'storybook/manager-api'; import { Button } from 'storybook/internal/components'; import { LightningIcon } from '@storybook/icons'; The [`useGlobals`](./addons-api#useglobals) and [`useStorybookApi`](./addons-api#usestorybookapi) hooks from the `manager-api` package are used to access the Storybook's APIs, allowing users to interact with the addon, such as enabling or disabling it. The `Button` component from the `storybook/internal/components` module can be used to render the buttons in the toolbar. The [`@storybook/icons`](https://github.com/storybookjs/icons) package provides a large set of appropriately sized and styled icons to choose from. src/Tool.tsx export const Tool = memo(function MyAddonSelector() { const [globals, updateGlobals] = useGlobals(); const api = useStorybookApi(); const isActive = [true, 'true'].includes(globals[PARAM_KEY]); const toggleMyTool = useCallback(() => { updateGlobals({ [PARAM_KEY]: !isActive, }); }, [isActive]); useEffect(() => { api.setAddonShortcut(ADDON_ID, { label: 'Toggle Addon [8]', defaultShortcut: ['8'], actionName: 'myaddon', showInMenu: false, action: toggleMyTool, }); }, [toggleMyTool, api]); return ( ); }); The `Tool` component is the entry point of the addon. It renders the UI elements in the toolbar, registers a keyboard shortcut, and handles the logic to enable and disable the addon. Moving onto the manager, here we register the addon with Storybook using a unique name and identifier. Since we've removed the `Panel` and `Tab` files, we'll need to adjust the file to only reference the addon we're building. src/manager.ts import { addons, types } from 'storybook/manager-api'; import { ADDON_ID, TOOL_ID } from './constants'; import { Tool } from './Tool'; // Register the addon addons.register(ADDON_ID, () => { // Register the tool addons.add(TOOL_ID, { type: types.TOOL, title: 'My addon', match: ({ tabId, viewMode }) => !tabId && viewMode === 'story', render: Tool, }); }); ### Conditionally render the addon Notice the `match` property. It allows you to control the view mode (story or docs) and tab (the story canvas or [custom tabs](./addon-types#tabs)) where the toolbar addon is visible. For example: * `({ tabId }) => tabId === 'my-addon/tab'` will show your addon when viewing the tab with the ID `my-addon/tab`. * `({ viewMode }) => viewMode === 'story'` will show your addon when viewing a story in the canvas. * `({ viewMode }) => viewMode === 'docs'` will show your addon when viewing the documentation for a component. * `({ tabId, viewMode }) => !tabId && viewMode === 'story'` will show your addon when viewing a story in the canvas and not in a custom tab (i.e. when `tabId === undefined`). Run the `start` script to build and start Storybook and verify that the addon is registered correctly and showing in the UI. ![Addon registered in the toolbar](/docs-assets/10.1/addons/storybook-addon-initial-state.png) ### Style the addon In Storybook, applying styles for addons is considered a side-effect. Therefore, we'll need to make some changes to our addon to allow it to use the styles when it is active and remove them when it's disabled. We're going to rely on two of Storybook's features to handle this: [decorators](../writing-stories/decorators) and [globals](../essentials/toolbars-and-globals#globals). To handle the CSS logic, we must include some helper functions to inject and remove the stylesheets from the DOM. Start by creating the helper file with the following content: src/helpers.ts import { global } from '@storybook/global'; export const clearStyles = (selector: string | string[]) => { const selectors = Array.isArray(selector) ? selector : [selector]; selectors.forEach(clearStyle); }; const clearStyle = (input: string | string[]) => { const selector = typeof input === 'string' ? input : input.join(''); const element = global.document.getElementById(selector); if (element && element.parentElement) { element.parentElement.removeChild(element); } }; export const addOutlineStyles = (selector: string, css: string) => { const existingStyle = global.document.getElementById(selector); if (existingStyle) { if (existingStyle.innerHTML !== css) { existingStyle.innerHTML = css; } } else { const style = global.document.createElement('style'); style.setAttribute('id', selector); style.innerHTML = css; global.document.head.appendChild(style); } }; Next, create the file with the styles we want to inject with the following content: src/OutlineCSS.ts import { dedent } from 'ts-dedent'; export default function outlineCSS(selector: string) { return dedent/* css */ ` ${selector} body { outline: 1px solid #2980b9 !important; } ${selector} article { outline: 1px solid #3498db !important; } ${selector} nav { outline: 1px solid #0088c3 !important; } ${selector} aside { outline: 1px solid #33a0ce !important; } ${selector} section { outline: 1px solid #66b8da !important; } ${selector} header { outline: 1px solid #99cfe7 !important; } ${selector} footer { outline: 1px solid #cce7f3 !important; } ${selector} h1 { outline: 1px solid #162544 !important; } ${selector} h2 { outline: 1px solid #314e6e !important; } ${selector} h3 { outline: 1px solid #3e5e85 !important; } ${selector} h4 { outline: 1px solid #449baf !important; } ${selector} h5 { outline: 1px solid #c7d1cb !important; } ${selector} h6 { outline: 1px solid #4371d0 !important; } ${selector} main { outline: 1px solid #2f4f90 !important; } ${selector} address { outline: 1px solid #1a2c51 !important; } ${selector} div { outline: 1px solid #036cdb !important; } ${selector} p { outline: 1px solid #ac050b !important; } ${selector} hr { outline: 1px solid #ff063f !important; } ${selector} pre { outline: 1px solid #850440 !important; } ${selector} blockquote { outline: 1px solid #f1b8e7 !important; } ${selector} ol { outline: 1px solid #ff050c !important; } ${selector} ul { outline: 1px solid #d90416 !important; } ${selector} li { outline: 1px solid #d90416 !important; } ${selector} dl { outline: 1px solid #fd3427 !important; } ${selector} dt { outline: 1px solid #ff0043 !important; } ${selector} dd { outline: 1px solid #e80174 !important; } ${selector} figure { outline: 1px solid #ff00bb !important; } ${selector} figcaption { outline: 1px solid #bf0032 !important; } ${selector} table { outline: 1px solid #00cc99 !important; } ${selector} caption { outline: 1px solid #37ffc4 !important; } ${selector} thead { outline: 1px solid #98daca !important; } ${selector} tbody { outline: 1px solid #64a7a0 !important; } ${selector} tfoot { outline: 1px solid #22746b !important; } ${selector} tr { outline: 1px solid #86c0b2 !important; } ${selector} th { outline: 1px solid #a1e7d6 !important; } ${selector} td { outline: 1px solid #3f5a54 !important; } ${selector} col { outline: 1px solid #6c9a8f !important; } ${selector} colgroup { outline: 1px solid #6c9a9d !important; } ${selector} button { outline: 1px solid #da8301 !important; } ${selector} datalist { outline: 1px solid #c06000 !important; } ${selector} fieldset { outline: 1px solid #d95100 !important; } ${selector} form { outline: 1px solid #d23600 !important; } ${selector} input { outline: 1px solid #fca600 !important; } ${selector} keygen { outline: 1px solid #b31e00 !important; } ${selector} label { outline: 1px solid #ee8900 !important; } ${selector} legend { outline: 1px solid #de6d00 !important; } ${selector} meter { outline: 1px solid #e8630c !important; } ${selector} optgroup { outline: 1px solid #b33600 !important; } ${selector} option { outline: 1px solid #ff8a00 !important; } ${selector} output { outline: 1px solid #ff9619 !important; } ${selector} progress { outline: 1px solid #e57c00 !important; } ${selector} select { outline: 1px solid #e26e0f !important; } ${selector} textarea { outline: 1px solid #cc5400 !important; } ${selector} details { outline: 1px solid #33848f !important; } ${selector} summary { outline: 1px solid #60a1a6 !important; } ${selector} command { outline: 1px solid #438da1 !important; } ${selector} menu { outline: 1px solid #449da6 !important; } ${selector} del { outline: 1px solid #bf0000 !important; } ${selector} ins { outline: 1px solid #400000 !important; } ${selector} img { outline: 1px solid #22746b !important; } ${selector} iframe { outline: 1px solid #64a7a0 !important; } ${selector} embed { outline: 1px solid #98daca !important; } ${selector} object { outline: 1px solid #00cc99 !important; } ${selector} param { outline: 1px solid #37ffc4 !important; } ${selector} video { outline: 1px solid #6ee866 !important; } ${selector} audio { outline: 1px solid #027353 !important; } ${selector} source { outline: 1px solid #012426 !important; } ${selector} canvas { outline: 1px solid #a2f570 !important; } ${selector} track { outline: 1px solid #59a600 !important; } ${selector} map { outline: 1px solid #7be500 !important; } ${selector} area { outline: 1px solid #305900 !important; } ${selector} a { outline: 1px solid #ff62ab !important; } ${selector} em { outline: 1px solid #800b41 !important; } ${selector} strong { outline: 1px solid #ff1583 !important; } ${selector} i { outline: 1px solid #803156 !important; } ${selector} b { outline: 1px solid #cc1169 !important; } ${selector} u { outline: 1px solid #ff0430 !important; } ${selector} s { outline: 1px solid #f805e3 !important; } ${selector} small { outline: 1px solid #d107b2 !important; } ${selector} abbr { outline: 1px solid #4a0263 !important; } ${selector} q { outline: 1px solid #240018 !important; } ${selector} cite { outline: 1px solid #64003c !important; } ${selector} dfn { outline: 1px solid #b4005a !important; } ${selector} sub { outline: 1px solid #dba0c8 !important; } ${selector} sup { outline: 1px solid #cc0256 !important; } ${selector} time { outline: 1px solid #d6606d !important; } ${selector} code { outline: 1px solid #e04251 !important; } ${selector} kbd { outline: 1px solid #5e001f !important; } ${selector} samp { outline: 1px solid #9c0033 !important; } ${selector} var { outline: 1px solid #d90047 !important; } ${selector} mark { outline: 1px solid #ff0053 !important; } ${selector} bdi { outline: 1px solid #bf3668 !important; } ${selector} bdo { outline: 1px solid #6f1400 !important; } ${selector} ruby { outline: 1px solid #ff7b93 !important; } ${selector} rt { outline: 1px solid #ff2f54 !important; } ${selector} rp { outline: 1px solid #803e49 !important; } ${selector} span { outline: 1px solid #cc2643 !important; } ${selector} br { outline: 1px solid #db687d !important; } ${selector} wbr { outline: 1px solid #db175b !important; }`; } Since the addon can be active in both the story and documentation modes, the DOM node for Storybook's preview `iframe` is different in these two modes. In fact, Storybook renders multiple story previews on one page when in documentation mode. Therefore, we'll need to choose the correct selector for the DOM node where the styles will be injected and ensure the CSS is scoped to that particular selector. That mechanism is provided as an example within the `src/withGlobals.ts` file, which we'll use to connect the styling and helper functions to the addon logic. Update the file to the following: src/withGlobals.ts import type { Renderer, PartialStoryFn as StoryFunction, StoryContext, } from 'storybook/internal/types'; import { useEffect, useMemo, useGlobals } from 'storybook/preview-api'; import { PARAM_KEY } from './constants'; import { clearStyles, addOutlineStyles } from './helpers'; import outlineCSS from './outlineCSS'; export const withGlobals = (StoryFn: StoryFunction, context: StoryContext) => { const [globals] = useGlobals(); const isActive = [true, 'true'].includes(globals[PARAM_KEY]); // Is the addon being used in the docs panel const isInDocs = context.viewMode === 'docs'; const outlineStyles = useMemo(() => { const selector = isInDocs ? `#anchor--${context.id} .docs-story` : '.sb-show-main'; return outlineCSS(selector); }, [context.id]); useEffect(() => { const selectorId = isInDocs ? `my-addon-docs-${context.id}` : `my-addon`; if (!isActive) { clearStyles(selectorId); return; } addOutlineStyles(selectorId, outlineStyles); return () => { clearStyles(selectorId); }; }, [isActive, outlineStyles, context.id]); return StoryFn(); }; ## Packaging and publishing Storybook addons, similar to most packages in the JavaScript ecosystem, are distributed as NPM packages. However, they have specific criteria that need to be met to be published to NPM and crawled by the integration catalog: 1. Have a `dist` folder with the transpiled code. 2. A `package.json` file declaring: * Module-related information * Integration catalog metadata ### Module Metadata The first category of metadata is related to the addon itself. This includes the entry for the module, which files to include when the addon is published. And the required configuration to integrate the addon with Storybook, allowing it to be used by its consumers. package.json { "exports": { ".": { "types": "./dist/index.d.ts", "node": "./dist/index.js", "require": "./dist/index.js", "import": "./dist/index.mjs" }, "./manager": "./dist/manager.mjs", "./preview": "./dist/preview.mjs", "./package.json": "./package.json" }, "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/index.d.ts", "files": ["dist/**/*", "README.md", "*.js", "*.d.ts"], "devDependencies": { "@storybook/addon-docs": "^9.0.0", "storybook": "^9.0.0" }, "bundler": { "exportEntries": ["src/index.ts"], "managerEntries": ["src/manager.ts"], "previewEntries": ["src/preview.ts"] } } ### Integration Catalog Metadata The second metadata category is related to the [integration catalog](https://storybook.js.org/integrations). Most of this information is already pre-configured by the Addon Kit. However, items like the display name, icon, and frameworks must be configured via the `storybook` property to be displayed in the catalog. package.json { "name": "my-storybook-addon", "version": "1.0.0", "description": "My first storybook addon", "author": "Your Name", "storybook": { "displayName": "My Storybook Addon", "unsupportedFrameworks": ["react-native"], "icon": "https://yoursite.com/link-to-your-icon.png" }, "keywords": ["storybook-addon", "appearance", "style", "css", "layout", "debug"] } ℹ️ The `storybook` configuration element includes additional properties that help customize the addon's searchability and indexing. For more information, see the [Integration catalog documentation](./integration-catalog). One essential item to note is the `keywords` property as it maps to the catalog's tag system. Adding the `storybook-addon` keyword ensures that the addon is discoverable in the catalog when searching for addons. The remaining keywords help with the searchability and categorization of the addon. ### Publishing to NPM Once you're ready to publish your addon to NPM, the Addon Kit comes pre-configured with the [Auto](https://github.com/intuit/auto) package for release management. It generates a changelog and uploads the package to NPM and GitHub automatically. Therefore, you need to configure access to both. 1. Authenticate using [npm adduser](https://docs.npmjs.com/cli/v9/commands/npm-adduser) 2. Generate a [access token](https://docs.npmjs.com/creating-and-viewing-access-tokens#creating-access-tokens) with both `read` and `publish` permissions. 3. Create a [personal access token](https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token) with `repo` and `workflow` scoped permissions. 4. Create a `.env` file in the root of your project and add the following: GH_TOKEN=value_you_just_got_from_github NPM_TOKEN=value_you_just_got_from_npm Next, run the following command to create labels on GitHub. You'll use these labels to categorize changes to the package. npx auto create-labels Finally, run the following command to create a release for your addon. This will build and package the addon code, bump the version, push the release into GitHub and npm, and generate a changelog. npm npm run release ### CI automation By default, the Addon Kit comes pre-configured with a GitHub Actions workflow, enabling you to automate the release management process. This ensures that the package is always up to date with the latest changes and that the changelog is updated accordingly. However, you'll need additional configuration to use your NPM and GitHub tokens to publish the package successfully. In your repository, click the **Settings** tab, then the **Secrets and variables** dropdown, followed by the **Actions** item. You should see the following screen: ![GitHub secrets page](/docs-assets/10.1/addons/github-secrets-screen.png) Then, click the **New repository secret** , name it `NPM_TOKEN`, and paste the token you generated earlier. Whenever you merge a pull request to the default branch, the workflow will run and publish a new release, automatically incrementing the version number and updating the changelog. **Learn more about the Storybook addon ecosystem** * [Types of addons](./addon-types) for other types of addons * Writing addons for the basics of addon development * [Presets](./writing-presets) for preset development * [Integration catalog](./integration-catalog) for requirements and available recipes * [API reference](./addons-api) to learn about the available APIs Was this page useful? 👍👎 [✍️ Edit on Github](https://github.com/storybookjs/storybook/tree/next/docs/addons/writing-addons.mdx) --- # Storybook Documentation # Source: https://storybook.js.org/docs/addons/writing-presets # Page: /docs/addons/writing-presets # Write a preset addon ReactVueAngularWeb ComponentsMore Storybook presets are pre-configured settings or configurations that enable developers quickly set up and customize their environment with a specific set of features, functionalities, or integrations. ## How presets work Preset addons allow developers to compose various configuration options and plugins via APIs to integrate with Storybook and customize its behavior and functionality. Typically, presets are separated into two files, each with its specific role. ### Local presets This type of preset allows you to encapsulate and organize configurations specific to the addon, including [builder](../builders) support, [Babel](https://babeljs.io/), or third-party integrations. For example: example-addon/src/preset.ts Typescript import { webpackFinal as webpack } from './webpack/webpackFinal'; import { viteFinal as vite } from './vite/viteFinal'; import { babelDefault as babel } from './babel/babelDefault'; export const webpackFinal = webpack as any; export const viteFinal = vite as any; export const babelDefault = babel as any; ### Root-level presets This type of preset is user-facing and responsible for registering the addon without any additional configuration from the user by bundling Storybook-related features (e.g., [parameters](../writing-stories/parameters)) via the [`previewAnnotations`](../api/main-config/main-config-preview-annotations) and UI related features (e.g., addons) via the `managerEntries` API. For example: example-addon/preset.js export const previewAnnotations = [import.meta.resolve('./dist/preview')]; export const managerEntries = [import.meta.resolve('./dist/manager')]; export * from './dist/preset.js'; ## Presets API When writing a preset, you can access a select set of APIs to interact with the Storybook environment, including the supported builders (e.g., Webpack, Vite), the Storybook configuration, and UI. Below are the available APIs you can use when writing a preset addon. ### Babel To customize Storybook's Babel configuration and add support for additional features, you can use the [`babelDefault`](../api/main-config/main-config-babel-default) API. It will apply the provided configuration ahead of any other user presets, which can be further customized by the end user via the [`babel`](../api/main-config/main-config-babel) configuration option. For example: example-addon/src/babel/babelDefault.ts Typescript import { TransformOptions } from '@babel/core'; export function babelDefault(config: TransformOptions) { return { ...config, plugins: [ ...config.plugins, [import.meta.resolve('@babel/plugin-transform-react-jsx'), {}, 'preset'], ], }; } ℹ️ The Babel configuration is only applied to frameworks that use Babel internally. If you enable it for a framework that uses a different compiler, like [SWC](https://swc.rs/) or [esbuild](https://esbuild.github.io/), it will be ignored. ### Builders By default, Storybook provides support for the leading industry builders, including [Webpack](../builders/webpack) and [Vite](../builders/vite). If you need additional features for any of these builders, you can use APIs to extend the builder configuration based on your specific needs. #### Vite If you are creating a preset and want to include Vite support, the `viteFinal` API can be used to modify the default configuration and enable additional features. For example: example-addon/src/vite/viteFinal.ts Typescript export function ViteFinal(config: any, options: any = {}) { config.plugins.push( new MyCustomPlugin({ someOption: true, }), ); return config; } #### Webpack To customize the Webpack configuration in Storybook to add support for additional file types, apply specific loaders, configure plugins, or make any other necessary modifications, you can use the `webpackFinal` API. Once invoked, it will extend the default Webpack configuration with the provided configuration. An example of this would be: example-addon/src/webpack/webpackFinal.ts Typescript import { fileURLtoPath } from 'node:url'; import type { Configuration as WebpackConfig } from 'webpack'; export function webpackFinal(config: WebpackConfig, options: any = {}) { const rules = [ ...(config.module?.rules || []), { test: /\.custom-file$/, loader: fileURLToPath(import.meta.resolve(`custom-loader`)), }, ]; config.module.rules = rules; return config; } ### ManagerEntries If you're writing a preset that loads third-party addons, which you may not have control over, but require access to specific features or additional configuration, you can use the `managerEntries` API. For example: example-addon/preset.js export const managerEntries = (entry = []) => { return [...entry, import.meta.resolve('path-to-third-party-addon')]; }; ### PreviewAnnotations If you need additional settings to render stories for a preset, like [decorators](../writing-stories/decorators) or [parameters](../writing-stories/parameters), you can use the `previewAnnotations` API. For example, to apply a decorator to all stories, create a preview file that includes the decorator and make it available to the preset as follows: CSF 3CSF Next 🧪 example-addon/src/preview.ts Typescript import type { Renderer, ProjectAnnotations } from 'storybook/internal/types'; import { PARAM_KEY } from './constants'; import { CustomDecorator } from './decorators'; const preview: ProjectAnnotations = { decorators: [CustomDecorator], globals: { [PARAM_KEY]: false, }, }; export default preview; ## Advanced configuration The presets API is designed to be flexible and allow you to customize Storybook to your specific needs, including using presets for more advanced use cases without publishing them. In such cases, you can rely on a private preset. These private presets contain configuration options meant for development purposes and not for end-users. The `.storybook/main.js|ts` file is an example of such a private preset that empowers you to modify the behavior and functionality of Storybook. CSF 3CSF Next 🧪 .storybook/main.ts Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, angular, etc. import type { StorybookConfig } from '@storybook/your-framework'; const config: StorybookConfig = { viteFinal: async (config, options) => { // Update config here return config; }, webpackFinal: async (config, options) => { // Change webpack config return config; }, babel: async (config, options) => { return config; }, }; export default config; ### Addons For addon consumers, the `managerEntries` API can be too technical, making it difficult to use. To make it easier to add addons to Storybook, the preset API provides the [`addons`](../api/main-config/main-config-addons) API, which accepts an array of addon names and will automatically load them for you. For example: CSF 3CSF Next 🧪 .storybook/main.ts Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { StorybookConfig } from '@storybook/your-framework'; const config: StorybookConfig = { addons: [ // Other Storybook addons '@storybook/addon-a11y', ], }; export default config; The array of values supports references to additional presets and addons that should be included in the manager. Storybook will automatically detect whether the provided value is a preset or an addon and load it accordingly. ### Entries Entries are the place to register entry points for the preview. This feature can be utilized to create a configure-storybook preset that automatically loads all `*.stories.js` files into Storybook, eliminating the need for users to copy-paste the same configuration repeatedly. ### UI configuration The Storybook preset API also provides access to the UI configuration, including the `head` and `body` HTML elements of the preview, configured by the [`previewHead`](../api/main-config/main-config-preview-head) and [`previewBody`](../api/main-config/main-config-preview-body) APIs. Both allow you to set up Storybook in a way that is similar to using the [`preview-head.html`](../configure/story-rendering#adding-to-head) and [`preview-body.html`](../configure/story-rendering#adding-to-body) files. These methods accept a string and return a modified version, injecting the provided content into the HTML element. Body (CSF 3)Head (CSF 3)Body (CSF Next 🧪)Head (CSF Next 🧪) .storybook/main.ts Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { StorybookConfig } from '@storybook/your-framework'; const config: StorybookConfig = { previewBody: (body) => ` ${body} ${ process.env.ANALYTICS_ID ? '' : '' } `, }; export default config; Additionally, if you need to customize the manager (i.e., where Storybook’s search, navigation, toolbars, and addons render), you can use the [`managerHead`](../api/main-config/main-config-manager-head) to modify the UI, similar to how you would do it with the `manager-head.html` file. For example: CSF 3CSF Next 🧪 .storybook/main.ts Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { StorybookConfig } from '@storybook/your-framework'; const config: StorybookConfig = { managerHead: (head) => ` ${head} `, }; export default config; However, if you need, you can also customize the template used by Storybook to render the UI. To do so, you can use the `previewMainTemplate` API and provide a reference for a custom template created as a `ejs` file. For an example of how to do this, see the [template](https://github.com/storybookjs/storybook/blob/next/code/builders/builder-webpack5/templates/preview.ejs) used by the Webpack 5 builder. ## Troubleshooting ### Storybook doesn't load files in my preset As Storybook relies on [esbuild](https://esbuild.github.io/) instead of Webpack to build the UI, presets that depend on the `managerWebpack` API to configure the manager or load additional files other than CSS or images will no longer work. We recommend removing it from your preset and adjusting your configuration to convert any additional files to JavaScript. **Learn more about the Storybook addon ecosystem** * [Types of addons](./addon-types) for other types of addons * [Writing addons](./writing-addons) for the basics of addon development * Presets for preset development * [Integration catalog](./integration-catalog) for requirements and available recipes * [API reference](./addons-api) to learn about the available APIs Was this page useful? 👍👎 [✍️ Edit on Github](https://github.com/storybookjs/storybook/tree/next/docs/addons/writing-presets.mdx) --- # Storybook Documentation # Source: https://storybook.js.org/docs/addons # Page: /docs/addons # Introduction to addons Addons extend Storybook with features and integrations that are not built into the core. Most Storybook features are implemented as addons. For instance: [documentation](./writing-docs), [accessibility testing](./writing-tests/accessibility-testing), [interactive controls](./essentials/controls), among others. The [addon API](./addons/addons-api) makes it easy for you to configure and customize Storybook in new ways. There are countless addons made by the community that unlocks time-saving workflows. Browse our [addon catalog](https://storybook.js.org/addons) to install an existing addon or as inspiration for your own addon. ## Storybook basics Before writing your first [addon](https://storybook.js.org/addons), let’s take a look at the basics of Storybook’s architecture. While Storybook presents a unified user interface, under the hood it’s divided down the middle into **Manager** and **Preview**. The **Manager** is the UI responsible for rendering the: * 🔍 Search * 🧭 Navigation * 🔗 Toolbars * 📦 Addons The **Preview** area is an `iframe` where your stories are rendered. ![Storybook detailed window](/docs-assets/10.1/addons/manager-preview.png) Because both elements run in their own separate `iframes`, they use a communication channel to keep in sync. For example, when you select a story in the Manager an event is dispatched across the channel notifying the Preview to render the story. ## Anatomy of an addon Storybook addons allow you to extend what's already possible with Storybook, everything from the [user interface](./addons/addon-types) to the [API](./addons/addons-api). Each one is classified into two broader categories. ### UI-based addons [UI-based addons](./addons/addon-types#ui-based-addons) focus on customizing Storybook's user interface to extend your development workflow. Examples of UI-based addons include: [Controls](./essentials/controls), [Docs](./writing-docs) and [Accessibility](./writing-tests/accessibility-testing). [Learn how to write an addon »](./addons/writing-addons) ### Preset addons [Preset addons](./addons/addon-types#preset-addons) help you integrate Storybook with other technologies and libraries. An examples of a preset addons is [preset-create-react-app](https://github.com/storybookjs/presets/tree/master/packages/preset-create-react-app). [Learn how to write a preset addon »](./addons/writing-presets) Was this page useful? 👍👎 [✍️ Edit on Github](https://github.com/storybookjs/storybook/tree/next/docs/addons/index.mdx) --- # Storybook Documentation # Source: https://storybook.js.org/docs/api/arg-types # Page: /docs/api/arg-types # ArgTypes ReactVueAngularWeb ComponentsMore ArgTypes specify the behavior of [args](../writing-stories/args). By specifying the type of an arg, you constrain the values that it can accept and provide information about args that are not explicitly set (i.e., description). You can also use argTypes to “annotate” args with information used by addons that make use of those args. For instance, to instruct the [controls panel](../essentials/controls) to render a color picker, you could specify the `'color'` control type. The most concrete realization of argTypes is the [`ArgTypes` doc block](./doc-blocks/doc-block-argtypes) ([`Controls`](./doc-blocks/doc-block-controls) is similar). Each row in the table corresponds to a single argType and the current value of that arg. ![ArgTypes table](/docs-assets/10.1/api/doc-block-argtypes.png) ## Automatic argType inference If you are using the Storybook [docs](../writing-docs) addon, then Storybook will infer a set of argTypes for each story based on the `component` specified in the [default export](../writing-stories/index#default-export) of the CSF file. To do so, Storybook uses various static analysis tools depending on your framework. Framework| Static analysis tool ---|--- React| [react-docgen](https://github.com/reactjs/react-docgen) (default) or [react-docgen-typescript](https://github.com/styleguidist/react-docgen-typescript) Vue| [vue-docgen-api](https://github.com/vue-styleguidist/vue-styleguidist/tree/dev/packages/vue-docgen-api) Angular| [compodoc](https://compodoc.app/) WebComponents| [custom-element.json](https://github.com/webcomponents/custom-elements-json) Ember| [YUI doc](https://github.com/ember-learn/ember-cli-addon-docs-yuidoc#documenting-components) The data structure of `argTypes` is designed to match the output of the these tools. Properties specified manually will override what is inferred. ## Manually specifying argTypes For most Storybook projects, argTypes are automatically inferred from your components. Any argTypes specified manually will override the inferred values. ArgTypes are most often specified at the meta (component) level, in the [default export](../writing-stories/index#default-export) of the CSF file: CSF 3CSF Next 🧪 Button.stories.ts|tsx Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Meta } from '@storybook/your-framework'; import { Button } from './Button'; const meta = { component: Button, argTypes: { // 👇 All Button stories expect a label arg label: { control: 'text', description: 'Overwritten description', }, }, } satisfies Meta; export default meta; They can apply to all stories when specified at the project (global) level, in the `preview.js|ts` configuration file: CSF 3CSF Next 🧪 .storybook/preview.ts Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Preview } from '@storybook/your-framework'; const preview = { argTypes: { // 👇 All stories expect a label arg label: { control: 'text', description: 'Overwritten description', }, }, } satisfies Preview; export default preview; Or they can apply only to a [specific story](../writing-stories/index#defining-stories): CSF 3CSF Next 🧪 Button.stories.ts|tsx Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Meta, StoryObj } from '@storybook/your-framework'; import { Button } from './Button'; const meta = { component: Button, } satisfies Meta; export default meta; type Story = StoryObj; export const Basic: Story = { argTypes: { // 👇 This story expects a label arg label: { control: 'text', description: 'Overwritten description', }, }, } satisfies Story; ## `argTypes` Type: { [key: string]: { control?: ControlType | { type: ControlType; /* See below for more */ } | false; description?: string; if?: Conditional; mapping?: { [key: string]: { [option: string]: any } }; name?: string; options?: string[]; table?: { category?: string; defaultValue?: { summary: string; detail?: string }; disable?: boolean; subcategory?: string; type?: { summary?: string; detail?: string }; }, type?: SBType | SBScalarType['name']; } } You configure argTypes using an object with keys matching the name of args. The value of each key is an object with the following properties: ### `control` Type: | ControlType | { type: ControlType, accept?: string; labels?: { [option: string]: string }; max?: number; min?: number; presetColors?: string[]; step?: number; } | false Default: 1. `'select'`, if `options` are specified 2. Else, inferred from `type` 3. Else, `'object'` Specify the behavior of the [controls panel](../essentials/controls) for the arg. If you specify a string, it's used as the `type` of the control. If you specify an object, you can provide additional configuration. Specifying `false` will prevent the control from rendering. CSF 3CSF Next 🧪 Example.stories.ts|tsx Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Meta } from '@storybook/your-framework'; import { Example } from './Example'; const meta = { component: Example, argTypes: { value: { control: { type: 'number', min: 0, max: 100, step: 10, }, }, }, } satisfies Meta; export default meta; #### `control.type` Type: `ControlType | null` Default: Inferred; `'select'`, if `options` are specified; falling back to `'object'` Specifies the type of control used to change the arg value with the [controls panel](../essentials/controls). Here are the available types, `ControlType`, grouped by the type of data they handle: Data type| ControlType| Description ---|---|--- **array**| `'object'`| Provides a JSON-based editor to handle the values of the array. Also allows editing in raw mode. `{ control: 'object' }` **boolean**| `'boolean'`| Provides a toggle for switching between possible states. `{ control: 'boolean' }` **enum**| `'check'`| Provides a set of stacked checkboxes for selecting multiple options. `{ control: 'check', options: ['email', 'phone', 'mail'] }` | `'inline-check'`| Provides a set of inlined checkboxes for selecting multiple options. `{ control: 'inline-check', options: ['email', 'phone', 'mail'] }` | `'radio'`| Provides a set of stacked radio buttons based on the available options. `{ control: 'radio', options: ['email', 'phone', 'mail'] }` | `'inline-radio'`| Provides a set of inlined radio buttons based on the available options. `{ control: 'inline-radio', options: ['email', 'phone', 'mail'] }` | `'select'`| Provides a select to choose a single value from the options. `{ control: 'select', options: [20, 30, 40, 50] }` | `'multi-select'`| Provides a select to choose multiple values from the options. `{ control: 'multi-select', options: ['USA', 'Canada', 'Mexico'] }` **number**| `'number'`| Provides a numeric input to include the range of all possible values. `{ control: { type: 'number', min:1, max:30, step: 2 } }` | `'range'`| Provides a range slider to include all possible values. `{ control: { type: 'range', min: 1, max: 30, step: 3 } }` **object**| `'file'`| Provides a file input that returns an array of URLs. Can be further customized to accept specific file types. `{ control: { type: 'file', accept: '.png' } }` | `'object'`| Provides a JSON-based editor to handle the object's values. Also allows editing in raw mode. `{ control: 'object' }` **string**| `'color'`| Provides a color picker to choose color values. Can be additionally configured to include a set of color presets. `{ control: { type: 'color', presetColors: ['red', 'green']} }` | `'date'`| Provides a datepicker to choose a date. `{ control: 'date' }` | `'text'`| Provides a freeform text input. `{ control: 'text' }` 💡 The `date` control will convert the date into a UNIX timestamp when the value changes. It's a known limitation that will be fixed in a future release. If you need to represent the actual date, you'll need to update the story's implementation and convert the value into a date object. #### `control.accept` Type: `string` When `type` is `'file'`, you can specify the file types that are accepted. The value should be a string of comma-separated MIME types. #### `control.labels` Type: `{ [option: string]: string }` Map `options` to labels. `labels` doesn't have to be exhaustive. If an option is not in the object's keys, it's used verbatim. #### `control.max` Type: `number` When `type` is `'number'` or `'range'`, sets the maximum allowed value. #### `control.min` Type: `number` When `type` is `'number'` or `'range'`, sets the minimum allowed value. #### `control.presetColors` Type: `string[]` When `type` is `'color'`, defines the set of colors that are available in addition to the general color picker. The values in the array should be valid CSS color values. #### `control.step` Type: `number` When `type` is `'number'` or `'range'`, sets the granularity allowed when incrementing/decrementing the value. ### `description` Type: `string` Default: Inferred Describe the arg. (If you intend to describe the type of the arg, you should use `table.type`, instead.) CSF 3CSF Next 🧪 Example.stories.ts|tsx Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Meta } from '@storybook/your-framework'; import { Example } from './Example'; const meta = { component: Example, argTypes: { value: { description: 'The value of the slider', }, }, } satisfies Meta; export default meta; ### `if` Type: { [predicateType: 'arg' | 'global']: string; eq?: any; exists?: boolean; neq?: any; truthy?: boolean; } Conditionally render an argType based on the value of another [arg](../writing-stories/args) or [global](../essentials/toolbars-and-globals). CSF 3CSF Next 🧪 Example.stories.ts|tsx Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Meta } from '@storybook/your-framework'; import { Example } from './Example'; const meta = { component: Example, argTypes: { parent: { control: 'select', options: ['one', 'two', 'three'] }, // 👇 Only shown when `parent` arg exists parentExists: { if: { arg: 'parent', exists: true } }, // 👇 Only shown when `parent` arg does not exist parentDoesNotExist: { if: { arg: 'parent', exists: false } }, // 👇 Only shown when `parent` arg value is truthy parentIsTruthy: { if: { arg: 'parent' } }, parentIsTruthyVerbose: { if: { arg: 'parent', truthy: true } }, // 👇 Only shown when `parent` arg value is not truthy parentIsNotTruthy: { if: { arg: 'parent', truthy: false } }, // 👇 Only shown when `parent` arg value is 'three' parentIsEqToValue: { if: { arg: 'parent', eq: 'three' } }, // 👇 Only shown when `parent` arg value is not 'three' parentIsNotEqToValue: { if: { arg: 'parent', neq: 'three' } }, // Each of the above can also be conditional on the value of a globalType, e.g.: // 👇 Only shown when `theme` global exists parentExists: { if: { global: 'theme', exists: true } }, }, } satisfies Meta; export default meta; ### `mapping` Type: `{ [key: string]: { [option: string]: any } }` Map `options` to values. When dealing with non-primitive values, you'll notice that you'll run into some limitations. The most obvious issue is that not every value can be represented as part of the `args` param in the URL, losing the ability to share and deeplink to such a state. Beyond that, complex values such as JSX cannot be synchronized between the manager (e.g., Controls panel) and the preview (your story). `mapping` doesn't have to be exhaustive. If the currently selected option is not listed, it's used verbatim. Can be used with `control.labels`. CSF 3CSF Next 🧪 Example.stories.ts|tsx Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Meta } from '@storybook/your-framework'; import { Example } from './Example'; const meta = { component: Example, argTypes: { label: { control: { type: 'select' }, options: ['Normal', 'Bold', 'Italic'], mapping: { Bold: Bold, Italic: Italic, }, }, }, } satisfies Meta; export default meta; ### `name` Type: `string` The `argTypes` object uses the name of the arg as the key. By default, that key is used when displaying the argType in Storybook. You can override the displayed name by specifying a `name` property. CSF 3CSF Next 🧪 Example.stories.ts|tsx Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Meta } from '@storybook/your-framework'; import { Example } from './Example'; const meta = { component: Example, argTypes: { actualArgName: { name: 'Friendly name', }, }, } satisfies Meta; export default meta; ⚠️ Be careful renaming args in this way. Users of the component you're documenting will not be able to use the documented name as a property of your component and the actual name will not displayed. For this reason, the `name` property is best used when defining an `argType` that is only used for documentation purposes and not an actual property of the component. For example, when [providing argTypes for each property of an object](https://stackblitz.com/edit/github-uplqzp?file=src/stories/Button.stories.tsx). ### `options` Type: `string[]` Default: Inferred If the arg accepts a finite set of values, you can specify them with `options`. If those values are [complex](../essentials/controls#dealing-with-complex-values), like JSX elements, you can use `mapping` to map them to string values. You can use `control.labels` to provide custom labels for the options. CSF 3CSF Next 🧪 Example.stories.ts|tsx Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Meta } from '@storybook/your-framework'; import { Example } from './Example'; const meta = { component: Example, argTypes: { icon: { options: ['arrow-up', 'arrow-down', 'loading'], }, }, } satisfies Meta; export default meta; ### `table` Type: { category?: string; defaultValue?: { detail?: string; summary: string; }; disable?: boolean; subcategory?: string; type?: { detail?: string; summary: string; }; } Default: Inferred Specify how the arg is documented in the [`ArgTypes` doc block](./doc-blocks/doc-block-argtypes), [`Controls` doc block](./doc-blocks/doc-block-controls), and [Controls panel](../essentials/controls). CSF 3CSF Next 🧪 Example.stories.ts|tsx Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Meta } from '@storybook/your-framework'; import { Example } from './Example'; const meta = { component: Example, argTypes: { value: { table: { defaultValue: { summary: 0 }, type: { summary: 'number' }, }, }, }, } satisfies Meta; export default meta; #### `table.category` Type: `string` Default: Inferred, in some frameworks Display the argType under a category heading, with the label specified by `category`. #### `table.defaultValue` Type: `{ detail?: string; summary: string }` Default: Inferred The documented default value of the argType. `summary` is typically used for the value itself, while `detail` is used for additional information. #### `table.disable` Type: `boolean` Set to `true` to remove the argType's row from the table. #### `table.readonly` Type: `boolean` Set to `true` to indicate that the argType is read-only. #### `table.subcategory` Type: `string` Display the argType under a subcategory heading (which displays under the [`category`] heading), with the label specified by `subcategory`. #### `table.type` Type: `{ detail?: string; summary: string }` Default: Inferred from `type` The documented type of the argType. `summary` is typically used for the type itself, while `detail` is used for additional information. If you need to specify the actual, semantic type, you should use `type`, instead. ### `type` Type: `'boolean' | 'function' | 'number' | 'string' | 'symbol' | SBType` The full type of `SBType` is: SBType interface SBBaseType { required?: boolean; raw?: string; } type SBScalarType = SBBaseType & { name: 'boolean' | 'string' | 'number' | 'function' | 'symbol'; }; type SBArrayType = SBBaseType & { name: 'array'; value: SBType; }; type SBObjectType = SBBaseType & { name: 'object'; value: Record; }; type SBEnumType = SBBaseType & { name: 'enum'; value: (string | number)[]; }; type SBIntersectionType = SBBaseType & { name: 'intersection'; value: SBType[]; }; type SBUnionType = SBBaseType & { name: 'union'; value: SBType[]; }; type SBOtherType = SBBaseType & { name: 'other'; value: string; }; type SBType = | SBScalarType | SBEnumType | SBArrayType | SBObjectType | SBIntersectionType | SBUnionType | SBOtherType; Default: Inferred Specifies the semantic type of the argType. When an argType is inferred, the information from the various tools is summarized in this property, which is then used to infer other properties, like `control` and `table.type`. If you only need to specify the documented type, you should use `table.type`, instead. CSF 3CSF Next 🧪 Example.stories.ts|tsx Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Meta } from '@storybook/your-framework'; import { Example } from './Example'; const meta = { component: Example, argTypes: { value: { type: 'number' }, }, } satisfies Meta; export default meta; ### `defaultValue` (⛔️ **Deprecated**) Type: `any` Define the default value of the argType. Deprecated in favor of defining the [`arg`](../writing-stories/args) value directly. CSF 3CSF Next 🧪 Example.stories.ts|tsx Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Meta } from '@storybook/your-framework'; import { Example } from './Example'; const meta = { component: Example, argTypes: { value: { // ❌ Deprecated defaultValue: 0, }, }, // ✅ Do this instead args: { value: 0, }, } satisfies Meta; export default meta; Was this page useful? 👍👎 [✍️ Edit on Github](https://github.com/storybookjs/storybook/tree/next/docs/api/arg-types.mdx) --- # Storybook Documentation # Source: https://storybook.js.org/docs/api/cli-options # Page: /docs/api/cli-options # CLI options The Storybook command line interface (CLI) is the main tool you use to build and develop Storybook. ℹ️ Storybook collects completely anonymous data to help us improve user experience. Participation is optional, and you may [opt-out](../configure/telemetry#how-to-opt-out) if you'd not like to share any information. ## CLI commands All of the following documentation is available in the CLI by running `storybook --help`. 💡 Passing options to these commands works slightly differently if you're using npm instead of Yarn. You must prefix all of your options with `--`. For example, `npm run storybook build -- -o ./path/to/build --quiet`. ### `dev` Compiles and serves a development build of your Storybook that reflects your source code changes in the browser in real-time. It should be run from the root of your project. storybook dev [options] Options include: Option| Description ---|--- `--help`| Output usage information. `storybook dev --help` `-V`, `--version`| Output the version number. `storybook dev -V` `-p`, `--port [number]`| Port to run Storybook. `storybook dev -p 9009` `--exact-port`| Attempts to run Storybook on the exact port number specified. If the port is already in use, Storybook will exit with an error message. `storybook dev -p 9009 --exact-port` `-h`, `--host [string]`| Host to run Storybook. `storybook dev -h my-host.com` `-c`, `--config-dir [dir-name]`| Storybook configuration directory. `storybook dev -c .storybook` `--loglevel [level]`| Controls level of logging during build. Available options: `silly`, `verbose`, `info` (default), `warn`, `error`, `silent` `storybook dev --loglevel warn` `--https`| Serve Storybook over HTTPS. Note: You must provide your own certificate information. `storybook dev --https` `--ssl-ca`| Provide an SSL certificate authority. (Optional with --https, required if using a self-signed certificate) `storybook dev --ssl-ca my-certificate` `--ssl-cert`| Provide an SSL certificate. (Required with --https) `storybook dev --ssl-cert my-ssl-certificate` `--ssl-key`| Provide an SSL key. (Required with --https) `storybook dev --ssl-key my-ssl-key` `--smoke-test`| Exit after successful start. `storybook dev --smoke-test` `--ci`| CI mode (skip interactive prompts, don't open browser). `storybook dev --ci` `--no-open`| Do not open Storybook automatically in the browser. `storybook dev --no-open` `--quiet`| Suppress verbose build output. `storybook dev --quiet` `--debug`| Outputs more logs in the CLI to assist debugging. `storybook dev --debug` `--debug-webpack`| Display final webpack configurations for debugging purposes. `storybook dev --debug-webpack` `--stats-json [dir-name]`| Write stats JSON to disk. Requires Webpack `storybook dev --stats-json /tmp/stats` `--no-version-updates`| Skips Storybook's update check. `storybook dev --no-version-updates` `--docs`| Starts Storybook in documentation mode. Learn more about it in [here](../writing-docs/build-documentation#preview-storybooks-documentation). `storybook dev --docs` `--initial-path [path]`| Configures the URL Storybook should open when it opens the browser for the first time. `storybook dev --initial-path=/docs/getting-started--docs` `--preview-url [path]`| Overrides the default Storybook preview with a custom built preview URL. `storybook dev --preview-url=http://localhost:1337/external-iframe.html` `--force-build-preview`| Forcefully builds Storybook's preview iframe. Useful if you're experiencing issues, or combined with `--preview-url` to ensure the preview is up-to-date. `storybook dev --force-build-preview` `--disable-telemetry`| Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry#how-to-opt-out). `storybook dev --disable-telemetry` `--enable-crash-reports`| Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry#crash-reports-disabled-by-default). `storybook dev --enable-crash-reports` `--preview-only`| Skips Storybook's manager from building and opens the app in "preview only" mode, which is designed to be used in [unsupported browsers](../sharing/publish-storybook#build-storybook-for-older-browsers). `storybook dev --preview-only` ⚠️ With the release of Storybook 8, the `-s` CLI flag was removed. We recommend using the [static directory](../configure/integration/images-and-assets#serving-static-files-via-storybook) instead if you need to serve static files. ### `build` Compiles your Storybook instance so it can be [deployed](../sharing/publish-storybook). It should be run from the root of your project. storybook build [options] Options include: Option| Description ---|--- `-h`, `--help`| Output usage information. `storybook build --help` `-V`, `--version`| Output the version number. `storybook build -V` `-o`, `--output-dir [dir-name]`| Directory where to store built files. `storybook build -o /my-deployed-storybook` `-c`, `--config-dir [dir-name]`| Storybook configuration directory. `storybook build -c .storybook` `--loglevel [level]`| Controls level of logging during build. Available options: `silly`, `verbose`, `info` (default), `warn`, `error`, `silent`. `storybook build --loglevel warn` `--quiet`| Suppress verbose build output. `storybook build --quiet` `--debug`| Outputs more logs in the CLI to assist debugging. `storybook build --debug` `--debug-webpack`| Display final webpack configurations for debugging purposes. `storybook build --debug-webpack` `--stats-json [dir-name]`| Write stats JSON to disk. Requires Webpack `storybook build --stats-json /tmp/stats` `--docs`| Builds Storybook in documentation mode. Learn more about it in [here](../writing-docs/build-documentation#publish-storybooks-documentation). `storybook build --docs` `--test`| Optimize Storybook's production build for performance and tests by removing unnecessary features with the `test` option. Learn more [here](../api/main-config/main-config-build). `storybook build --test` `--preview-url [path]`| Overrides the default Storybook preview with a custom built preview URL. `storybook build --preview-url=http://localhost:1337/external-iframe.html` `--force-build-preview`| Forcefully builds Storybook's preview iframe. Useful if you're experiencing issues, or combined with `--preview-url` to ensure the preview is up-to-date. `storybook build --force-build-preview` `--disable-telemetry`| Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry#how-to-opt-out). `storybook build --disable-telemetry` `--enable-crash-reports`| Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry#crash-reports-disabled-by-default). `storybook build --enable-crash-reports` `--preview-only`| Skips Storybook's manager from building and produces a "preview only" app, which is designed to be used in [unsupported browsers](../sharing/publish-storybook#build-storybook-for-older-browsers). `storybook build --preview-only` ### `init` ℹ️ We recommend `create-storybook` for new projects. The `init` command will remain available for backwards compatibility. Installs and initializes the specified version (e.g., `@latest`, `@8`, `@next`) of Storybook into your project. If no version is specified, the latest version is installed. Read more in the [installation guide](../get-started/install). storybook[@version] init [options] For example, `storybook@8.4 init` will install Storybook 8.4 into your project. Options include: Option| Description ---|--- `-h`, `--help`| Output usage information. `storybook init --help` `-b`, `--builder`| Defines the [builder](../builders) to use for your Storybook instance. `storybook init --builder webpack5` `-f`, `--force`| Forcefully installs Storybook into your project, prompting you to overwrite existing files. `storybook init --force` `-s`, `--skip-install`| Skips the dependency installation step. Used only when you need to configure Storybook manually. `storybook init --skip-install` `-t`, `--type`| Defines the [framework](../configure/integration/frameworks) to use for your Storybook instance. `storybook init --type solid` `-y`, `--yes`| Skips interactive prompts and automatically installs Storybook per specified version, including all features. `storybook init --yes` `--features [...values]`| Use these features when installing, skipping the prompt. Supported values are `docs`, `test`, and `a11y`, space separated. `storybook init --features docs test a11y` `--package-manager`| Sets the package manager to use when installing Storybook. Available package managers include `npm`, `yarn`, and `pnpm`. `storybook init --package-manager pnpm` `--use-pnp`| Enables [Plug'n'Play](https://yarnpkg.com/features/pnp) support for Yarn. This option is only available when using Yarn as your package manager. `storybook init --use-pnp` `-p`, `--parser`| Sets the [jscodeshift parser](https://github.com/facebook/jscodeshift#parser). Available parsers include `babel`, `babylon`, `flow`, `ts`, and `tsx`. `storybook init --parser tsx` `--debug`| Outputs more logs in the CLI to assist debugging. `storybook init --debug` `--disable-telemetry`| Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry#how-to-opt-out). `storybook init --disable-telemetry` `--enable-crash-reports`| Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry#crash-reports-disabled-by-default). `storybook init --enable-crash-reports` `--loglevel `| Controls level of logging during initialization. Available options: `trace`, `debug`, `info` (default), `warn`, `error`, `silent` `storybook init --loglevel debug` `--logfile [path]`| Write all debug logs to the specified file at the end of the run. Defaults to debug-storybook.log when [path] is not provided. `storybook init --logfile /tmp/debug-storybook.log` `--no-dev`| Complete the initialization of Storybook without running the Storybook dev server. `storybook init --no-dev` ### `add` Installs a Storybook addon and configures your project for it. Read more in the [addon installation guide](../addons/install-addons). storybook add [addon] [options] Options include: Option| Description ---|--- `-h`, `--help`| Output usage information. `storybook add --help` `-c`, `--config-dir`| Storybook configuration directory. `storybook migrate --config-dir .storybook` `--package-manager`| Sets the package manager to use when installing the addon. Available package managers include `npm`, `yarn`, and `pnpm`. `storybook add [addon] --package-manager pnpm` `-s`, `--skip-postinstall`| Skips post-install configuration. Used only when you need to configure the addon yourself. `storybook add [addon] --skip-postinstall` `--debug`| Outputs more logs in the CLI to assist debugging. `storybook add --debug` `--loglevel `| Controls level of logging during addon installation. Available options: `trace`, `debug`, `info` (default), `warn`, `error`, `silent` `storybook add [addon] --loglevel debug` `--logfile [path]`| Write all debug logs to the specified file at the end of the run. Defaults to debug-storybook.log when [path] is not provided. `storybook add [addon] --logfile /tmp/debug-storybook.log` ### `remove` Deletes a Storybook addon from your project. Read more in the [addon installation guide](../addons/install-addons#removing-addons). storybook remove [addon] [options] Options include: Option| Description ---|--- `-h`, `--help`| Output usage information. `storybook remove --help` `--package-manager`| Sets the package manager to use when removing the addon. Available package managers include `npm`, `yarn`, and `pnpm`. `storybook remove [addon]--package-manager pnpm` `--debug`| Outputs more logs in the CLI to assist debugging. `storybook remove --debug` `--disable-telemetry`| Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry#how-to-opt-out). `storybook remove --disable-telemetry` `--enable-crash-reports`| Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry#crash-reports-disabled-by-default). `storybook remove --enable-crash-reports` ### `upgrade` Upgrades your Storybook instance to the specified version (e.g., `@latest`, `@8`, `@next`). Read more in the [upgrade guide](../releases/upgrading). storybook[@version] upgrade [options] For example, `storybook@latest upgrade --dry-run` will perform a dry run (no actual changes) of upgrading your project to the latest version of Storybook. Options include: Option| Description ---|--- `-h`, `--help`| Output usage information. `storybook upgrade --help` `-c, --config-dir `| Directory or directories to find Storybook configurations `storybook upgrade --config-dir .storybook` `-n`, `--dry-run`| Checks for version upgrades without installing them. `storybook upgrade --dry-run` `-s`, `--skip-check`| Skips the migration check step during the upgrade process. `storybook upgrade --skip-check` `-y`, `--yes`| Skips interactive prompts and automatically upgrades Storybook to the latest version. `storybook upgrade --yes` `-f`,`--force`| Force the upgrade, skipping autoblockers check. `storybook upgrade --force` `--package-manager`| Sets the package manager to use when upgrading Storybook. Available package managers include `npm`, `yarn`, and `pnpm`. `storybook upgrade --package-manager pnpm` `--debug`| Outputs more logs in the CLI to assist debugging. `storybook upgrade --debug` `--disable-telemetry`| Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry#how-to-opt-out). `storybook upgrade --disable-telemetry` `--enable-crash-reports`| Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry#crash-reports-disabled-by-default). `storybook upgrade --enable-crash-reports` `-logfile [path]`| Write all debug logs to the specified file at the end of the run. Defaults to debug-storybook.log when [path] is not provided. `storybook upgrade --logfile /tmp/debug-storybook.log` `--loglevel `| Define log level: `debug`, `error`, `info`, `silent`, `trace`, or `warn` (default: `info`). `storybook upgrade --loglevel debug` ### `migrate` Runs the provided codemod to ensure your Storybook project is compatible with the specified version. Read more in the [migration guide](../releases/upgrading). storybook[@version] migrate [codemod] [options] ℹ️ The command requires the codemod name (e.g., `csf-2-to-3`) as an argument to apply the necessary changes to your project. You can find the list of available codemods by running `storybook migrate --list`. For example, `storybook@latest migrate csf-2-to-3 --dry-run`, checks your project to verify if the codemod can be applied without making any changes, providing you with a report of which files would be affected. Options include: Option| Description ---|--- `-h`, `--help`| Output usage information. `storybook migrate --help` `-c`, `--config-dir`| Storybook configuration directory. `storybook migrate --config-dir .storybook` `-n`, `--dry-run`| Verify the migration exists and show the files to which it will be applied. `storybook migrate --dry-run` `-l`, `--list`| Shows a list of available codemods. `storybook migrate --list` `-g`, `--glob`| Glob for files upon which to apply the codemods. `storybook migrate --glob src/**/*.stories.tsx` `-p`, `--parser`| Sets the [jscodeshift parser](https://github.com/facebook/jscodeshift#parser). Available parsers include `babel`, `babylon`, `flow`, `ts`, and `tsx`. `storybook migrate --parser tsx` `-r`, `--rename [from-to]`| Renames the files affected by the codemod to include the provided suffix. `storybook migrate --rename ".js:.ts"` `--debug`| Outputs more logs in the CLI to assist debugging. `storybook migrate --debug` ### `automigrate` Perform standard configuration checks to determine if your Storybook project can be automatically migrated to the specified version. Read more in the [migration guide](../releases/upgrading#automigrate-script). storybook[@version] automigrate [fixId] [options] For example, `storybook@latest automigrate --dry-run` scans your project for potential migrations that can be applied automatically without making any changes. Options include: Option| Description ---|--- `-h`, `--help`| Output usage information. `storybook automigrate --help` `-c`, `--config-dir`| Storybook configuration directory. `storybook automigrate --config-dir .storybook` `-n`, `--dry-run`| Checks for available migrations without applying them. `storybook automigrate --dry-run` `-s`, `--skip-install`| Skip installing dependencies whenever applicable. `storybook automigrate --skip-install` `-y`, `--yes`| Applies available migrations automatically without prompting for confirmation. `storybook automigrate --yes` `-l`, `--list`| Shows a list of available automigrations. `storybook automigrate --list` `--package-manager`| Sets the package manager to use when running the auto migration. Available package managers include `npm`, `yarn`, and `pnpm`. `storybook automigrate --package-manager pnpm` `--renderer`| Specifies Storybook's renderer to use when running the automigration. Useful for monorepo environments where multiple Storybook instances can exist in the same project. `storybook automigrate --renderer vue` `--debug`| Outputs more logs in the CLI to assist debugging. `storybook automigrate --debug` `--disable-telemetry`| Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry#how-to-opt-out). `storybook automigrate --disable-telemetry` `--enable-crash-reports`| Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry#crash-reports-disabled-by-default). `storybook automigrate --enable-crash-reports` ### `doctor` Performs a health check on your Storybook project for common issues (e.g., duplicate dependencies, incompatible addons or mismatched versions) and provides suggestions on how to fix them. Applicable when [upgrading](../releases/upgrading#verifying-the-upgrade) Storybook versions. storybook doctor [options] Options include: Option| Description ---|--- `-h`, `--help`| Output usage information. `storybook doctor --help` `-c`, `--config-dir`| Storybook configuration directory. `storybook doctor --config-dir .storybook` `--package-manager`| Sets the package manager to use when running the health check. Available package managers include `npm`, `yarn`, and `pnpm`. `storybook doctor --package-manager pnpm` `--debug`| Outputs more logs in the CLI to assist debugging. `storybook doctor --debug` ### `info` Reports useful debugging information about your environment. Helpful in providing information when opening an issue or a discussion. storybook info Example output: Storybook Environment Info: System: OS: macOS 14.2 CPU: (8) arm64 Apple M3 Shell: 5.9 - /bin/zsh Binaries: Node: 18.19.0 - ~/.nvm/versions/node/v18.19.0/bin/node npm: 10.2.3 - ~/.nvm/versions/node/v18.19.0/bin/npm <----- active Browsers: Chrome: 120.0.6099.199 npmPackages: @storybook/addon-onboarding: ^1.0.10 => 1.0.10 @storybook/react: ^7.6.6 => 7.6.6 @storybook/react-vite: ^7.6.6 => 7.6.6 storybook: ^7.6.6 => 7.6.6 npmGlobalPackages: chromatic: ^10.2.0 => 10.2.0 ### `index` Build an `index.json` that lists all stories and docs entries in your Storybook. storybook index [options] Options include: Option| Description ---|--- `-o`, `--output-file `| JSON file to output index `-c`, `--config-dir `| Storybook configuration directory `--quiet`| Suppress verbose build output `--loglevel `| Control level of logging during build `--disable-telemetry`| Disables Storybook's telemetry `--debug`| Outputs more logs in the CLI to assist debugging. `--enable-crash-reports`| Enables sending crash reports to Storybook's telemetry ### `sandbox` Generates a local sandbox project using the specified version (e.g., `@latest`, `@8`, `@next`) for testing Storybook features based on the list of supported [frameworks](../configure/integration/frameworks). Useful for reproducing bugs when opening an issue or a discussion. storybook[@version] sandbox [framework-filter] [options] For example, `storybook@next sandbox` will generated sandboxes using the newest pre-release version of Storybook. The `framework-filter` argument is optional and can filter the list of available frameworks. For example, `storybook@next sandbox react` will only offer to generate React-based sandboxes. Options include: Option| Description ---|--- `-h`, `--help`| Output usage information. `storybook sandbox --help` `-o`, `--output [dir-name]`| Configures the location of the sandbox project. `storybook sandbox --output /my-sandbox-project` `--no-init`| Generates a sandbox project without initializing Storybook. `storybook sandbox --no-init` `--debug`| Outputs more logs in the CLI to assist debugging. `storybook sandbox --debug` `--disable-telemetry`| Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry#how-to-opt-out). `storybook sandbox --disable-telemetry` `--enable-crash-reports`| Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry#crash-reports-disabled-by-default). `storybook sandbox --enable-crash-reports` ℹ️ If you're looking for a hosted version of the available sandboxes, see [storybook.new](https://storybook.new). ## `create-storybook` To streamline the process of creating a new Storybook project, a separate CLI called `create-storybook` is provided. Package managers such as npm, pnpm, and Yarn will execute this command when running `create storybook`. You can specify a version (e.g., `@latest`, `@8`, `@next`) or it will default to the latest version. Read more in the [installation guide](../get-started/install). create storybook[@version] [options] For example, `create storybook@8.6` will install Storybook 8.6 into your project. Options include: Option| Description ---|--- `-h`, `--help`| Output usage information. `create storybook --help` `-b`, `--builder`| Defines the [builder](../builders) to use for your Storybook instance. `create storybook --builder webpack5` `-f`, `--force`| Forcefully installs Storybook into your project, prompting you to overwrite existing files. `create storybook --force` `-s`, `--skip-install`| Skips the dependency installation step. Used only when you need to configure Storybook manually. `create storybook --skip-install` `-t`, `--type`| Defines the [framework](../configure/integration/frameworks) to use for your Storybook instance. `create storybook --type solid` `-y`, `--yes`| Skips interactive prompts and automatically installs Storybook per specified version, including all features. `create storybook --yes` `--features [...values]`| Use these features when installing, skipping the prompt. Supported values are `docs`, `test`, and `a11y`, space separated. `create storybook --features docs test a11y` `--package-manager`| Sets the package manager to use when installing Storybook. Available package managers include `npm`, `yarn`, and `pnpm`. `create storybook --package-manager pnpm` `--use-pnp`| Enables [Plug'n'Play](https://yarnpkg.com/features/pnp) support for Yarn. This option is only available when using Yarn as your package manager. `create storybook --use-pnp` `-p`, `--parser`| Sets the [jscodeshift parser](https://github.com/facebook/jscodeshift#parser). Available parsers include `babel`, `babylon`, `flow`, `ts`, and `tsx`. `create storybook --parser tsx` `--debug`| Outputs more logs in the CLI to assist debugging. `create storybook --debug` `--disable-telemetry`| Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry#how-to-opt-out). `create storybook --disable-telemetry` `--enable-crash-reports`| Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry#crash-reports-disabled-by-default). `create storybook --enable-crash-reports` `--loglevel `| Controls level of logging during initialization. Available options: `trace`, `debug`, `info` (default), `warn`, `error`, `silent` `storybook init --loglevel debug` `--logfile [path]`| Write all debug logs to the specified file at the end of the run. Defaults to debug-storybook.log when [path] is not provided. `storybook init --logfile /tmp/debug-storybook.log` `--no-dev`| Complete the initialization of Storybook without running the Storybook dev server. `create storybook --no-dev` Was this page useful? 👍👎 [✍️ Edit on Github](https://github.com/storybookjs/storybook/tree/next/docs/api/cli-options.mdx) --- # Storybook Documentation # Source: https://storybook.js.org/docs/api/csf # Page: /docs/api/csf # Component Story Format (CSF) ReactVueAngularWeb ComponentsMore CSF 3[CSF Next (Preview)](./csf/csf-next) Component Story Format (CSF) is the recommended way to [write stories](./../writing-stories). It's an open standard based on ES6 modules that is portable beyond Storybook. In CSF, stories and component metadata are defined as ES Modules. Every component story file consists of a required [default export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export#Using_the_default_export) and one or more [named exports](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export). ## Default export The default export defines metadata about your component, including the `component` itself, its `title` (where it will show up in the [navigation UI story hierarchy](./../writing-stories/naming-components-and-hierarchy#sorting-stories)), [decorators](./../writing-stories/decorators), and [parameters](./../writing-stories/parameters). The `component` field is required and used by addons for automatic prop table generation and display of other component metadata. The `title` field is optional and should be unique (i.e., not re-used across files). CSF 3CSF Next 🧪 MyComponent.stories.ts|tsx Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Meta } from '@storybook/your-framework'; import { MyComponent } from './MyComponent'; const meta = { /* 👇 The title prop is optional. * See https://storybook.js.org/docs/configure/#configure-story-loading * to learn how to generate automatic titles */ title: 'Path/To/MyComponent', component: MyComponent, decorators: [ /* ... */ ], parameters: { /* ... */ }, } satisfies Meta; export default meta; For more examples, see [writing stories](./../writing-stories). ## Named story exports With CSF, every named export in the file represents a story object by default. CSF 3CSF Next 🧪 MyComponent.stories.ts|tsx Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc. import type { Meta, StoryObj } from '@storybook/your-framework'; import { MyComponent } from './MyComponent'; const meta = { component: MyComponent, } satisfies Meta; export default meta; type Story = StoryObj; export const Basic: Story = {}; export const WithProp: Story = { render: () => , }; The exported identifiers will be converted to "start case" using Lodash's [startCase](https://lodash.com/docs/#startCase) function. For example: Identifier| Transformation ---|--- name| Name someName| Some Name someNAME| Some NAME some_custom_NAME| Some Custom NAME someName1234| Some Name 1 2 3 4 We recommend that all export names to start with a capital letter. Story objects can be annotated with a few different fields to define story-level [decorators](./../writing-stories/decorators) and [parameters](./../writing-stories/parameters), and also to define the `name` of the story. Storybook's `name` configuration element is helpful in specific circumstances. Common use cases are names with special characters or Javascript restricted words. If not specified, Storybook defaults to the named export. CSF 3CSF Next 🧪 MyComponent.stories.ts|tsx Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Meta, StoryObj } from '@storybook/your-framework'; import { MyComponent } from './MyComponent'; const meta = { component: MyComponent, } satisfies Meta; export default meta; type Story = StoryObj; export const Simple: Story = { name: 'So simple!', // ... }; ## Args story inputs Starting in SB 6.0, stories accept named inputs called Args. Args are dynamic data that are provided (and possibly updated by) Storybook and its addons. Consider Storybook’s ["Button" example](./../writing-stories/index#defining-stories) of a text button that logs its click events: CSF 3CSF Next 🧪 Button.stories.ts|tsx Typescript // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc. import type { Meta, StoryObj } from '@storybook/your-framework'; import { action } from 'storybook/actions'; import { Button } from './Button'; const meta = { component: Button, } satisfies Meta; export default meta; type Story = StoryObj; export const Basic: Story = { render: () =>