---
title: Using Storybook
description: Easily use Bamboo with Storybook with our dedicated integration.
---

## Setup

We are assuming that you already have a project set up with a framework like React, Vue or Svelte.

<Steps>

### Install Storybook

Storybook needs to be installed into a project that is already set up with a framework. It will not work on an empty
project.

<Tabs items={['pnpm', 'npm', 'yarn', 'bun']}>
{/* <!-- prettier-ignore-start --> */}
  <Tab>
    ```bash
    pnpm dlx storybook@latest init
    ```
  </Tab>
  <Tab>
    ```bash
    npx storybook@latest init
    ```
  </Tab>
  <Tab>
    ```bash
    yarn dlx storybook@latest init
    ```
  </Tab>
  <Tab>
    ```bash
    bunx storybook@latest init
    ```
  </Tab>
{/* <!-- prettier-ignore-end --> */}
</Tabs>

### Install Bamboo

Install bamboo and create your `bamboo.config.ts` file.

<Tabs items={['pnpm', 'npm', 'yarn', 'bun']}>
  {/* <!-- prettier-ignore-start --> */}
  <Tab>
    ```bash
    pnpm install -D @bamboocss/dev
    pnpm bamboo init --postcss
    ```
  </Tab>
  <Tab>
    ```bash
    npm install -D @bamboocss/dev
    npx bamboo init --postcss
    ```
  </Tab>
  <Tab>
    ```bash
    yarn add -D @bamboocss/dev
    yarn bamboo init --postcss
    ```
  </Tab>
  <Tab>
    ```bash
    bun add -D @bamboocss/dev
    bun bamboo init --postcss
    ```
  </Tab>
  {/* <!-- prettier-ignore-end --> */}
</Tabs>

Storybook's Vite builder needs the array form of the plugin list. Both forms are equivalent to Bamboo; only the builder
cares. Change `postcss.config.cjs`:

```diff filename="postcss.config.cjs"
module.exports = {
-  plugins: {
-   '@bamboocss/dev/postcss': {}
-  }
+  plugins: [require('@bamboocss/dev/postcss')()]
}
```

### Update package.json scripts

Add `"prepare": "bamboo codegen"` to `scripts`. It runs [codegen](/docs/references/cli#codegen) after every dependency
install, so the output directory can stay in `.gitignore`.

### Configure the content

Make sure that all of the paths of your Storybook components are included in the `include` section of the
`bamboo.config.ts` file.

```ts {7} filename="bamboo.config.ts"
import { defineConfig } from '@bamboocss/dev'

export default defineConfig({
  // Whether to use css reset
  preflight: true,
  // Where to look for your css declarations
  include: ['./src/**/*.{js,jsx,ts,tsx}', './pages/**/*.{js,jsx,ts,tsx}', './stories/**/*.{js,jsx,ts,tsx}'],
  // Files to exclude
  exclude: [],
  // The output directory for your css system
  outdir: 'styled-system',
})
```

### Configure the entry CSS with layers

Locate your main CSS file and add the following layers:

```css filename="src/index.css"
@layer reset, base, tokens, recipes, utilities;
```

### Import the CSS in your Storybook config

Locate your `.storybook/preview.ts` file and import the CSS file.

In this example CSS file is located in the `src` folder.

```ts {1} filename=".storybook/preview.ts"
import '../src/index.css'

import type { Preview } from '@storybook/react'

const preview: Preview = {
  parameters: {
    actions: { argTypesRegex: '^on[A-Z].*' },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/,
      },
    },
  },
}

export default preview
```

### Start the Storybook server

Start the Storybook server with `pnpm storybook`.

### Start using Bamboo

```tsx filename="src/stories/Button.tsx"
import type { ReactNode } from 'react'
import { css } from '../../styled-system/css'

export const Button = ({ children }: { children: ReactNode }) => (
  <button className={css({ bg: 'red.300', px: '4', py: '3', _hover: { bg: 'red.400' } })}>{children}</button>
)
```

Stories pick the styles up with no extra configuration, as long as the story files are covered by `include`.

</Steps>

## Configuring Dark Mode

To enable dark mode in Storybook, you can use the `@storybook/addon-themes` package.

```bash
pnpm add -D @storybook/addon-themes
```

Then, update your `.storybook/preview.ts` file to include the following:

```ts filename=".storybook/preview.ts"
import { withThemeByClassName } from '@storybook/addon-themes'
import type { Preview, ReactRenderer } from '@storybook/react'

const preview: Preview = {
  // ...
  decorators: [
    withThemeByClassName<ReactRenderer>({
      themes: {
        light: '',
        dark: 'dark',
      },
      defaultTheme: 'light',
    }),
  ],
}

export default preview
```

With that in place, you should see the light/dark switcher in Storybook's toolbar.

## Troubleshooting

### Cannot find postcss plugin

If you are having issues with the PostCSS plugin similar to `Cannot find module '@bamboocss/dev/postcss'`, pass the
plugin uncalled instead:

```js filename="postcss.config.cjs"
module.exports = {
  plugins: [require('@bamboocss/dev/postcss')],
}
```

### HMR not triggered

If you are having issues with HMR not being triggered after a `bamboo.config.ts` change (or one of its
[dependencies](/docs/references/config#dependencies)), you can manually specify the files that should trigger a rebuild
by adding the following to your `bamboo.config.ts`:

```js filename="bamboo.config.ts"
import { defineConfig } from '@bamboocss/dev'

export default defineConfig({
  // ...
  dependencies: ['path/to/files/**.ts'],
})
```

### Styles in `args` is not generated

If you are having issues with your `args` not generating the expected CSS, it's probably because of:

- you didn't add a file glob for the Storybook files in your [`config.include`](/docs/references/config#include) like
  `"./stories/**/*.{js,jsx,ts,tsx}"`
- you didn't wrap your `args` object (or some part of it) with the
  [`.raw()` marker that helps Bamboo find style usage](/docs/guides/dynamic-styling#alternative)

```tsx filename="stories/Button.stories.tsx"
import type { Meta, StoryObj } from '@storybook/react'
import { button } from '../../styled-system/recipes'

export const Funky: Story = {
  // mark this as a button recipe usage
  args: button.raw({
    visual: 'funky',
    shape: 'circle',
    size: 'sm',
  }),
}
```

### Some recipes styles are missing

If you are having issues with your config `recipes` or `slotRecipes` not generating the expected CSS, it's probably
because of:

- you didn't add a file glob for the Storybook files in your [`config.include`](/docs/references/config#include) like
  `"./stories/**/*.{js,jsx,ts,tsx}"`
- you haven't used every recipes variants in your app, so you might want to pre-generate it (only for storybook usage)
  with [`staticCss`](/docs/guides/static)

```tsx filename="bamboo.config.ts"
import { defineConfig } from '@bamboocss/dev'

export default defineConfig({
  // ...
  staticCss: {
    recipes: '*',
  },
})
```
