Using Storybook
Easily use Panda with Storybook with our dedicated integration.
Learn how to set up Panda CSS in a Storybook project using PostCSS.
Setup
We are assuming that you already have a project set up with a framework like React, Vue or Svelte.
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.
Install Panda
Install panda and create your panda.config.ts
file.
If you are using Storybook with the Vite builder, you will have to update your PostCSS config file to use the array
syntax for the plugins instead of the object syntax. Simply change postcss.config.[c]js
:
postcss.config.js
module.exports = {
- plugins: {
- '@pandacss/dev/postcss': {}
- }
+ plugins: [require('@pandacss/dev/postcss')()]
}
Update package.json scripts
Open your package.json
file and update the scripts
section as follows:
web/package.json
{
"scripts": {
+ "prepare": "panda codegen"
}
}
"prepare"
- script that will run Panda CSS CLI codegen before each build. Read more about codegen in the CLI section.
This step ensures that the panda output directory is regenerated after each dependency installation. So you can add
the output directory to your .gitignore
file and not worry about it.
Configure the content
Make sure that all of the paths of your Storybook components are included in the include
section of the
panda.config.ts
file.
panda.config.ts
import { defineConfig } from '@pandacss/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:
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.
.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
Run the following command to start your Storybook server.
Start using Panda
Now you can start using Panda CSS in Storybook.
Here is the example of a Button component and its corresponding Storybook story:
src/stories/Button.tsx
import { ReactNode } from 'react'
import { css } from '../../styled-system/css'
export interface IButtonProps {
children: ReactNode
}
export const Button = ({ children }: IButtonProps) => {
return (
<button
className={css({
bg: 'red.300',
fontFamily: 'Inter',
px: '4',
py: '3',
borderRadius: 'md',
_hover: { bg: 'red.400' }
})}
>
{children}
</button>
)
}
src/stories/Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react'
import { css } from '../../styled-system/css'
import { Button } from './Button'
const meta = {
title: 'Example/Button',
component: Button,
tags: ['autodocs'],
decorators: [
Story => (
<div className={css({ m: 10 })}>
<Story />
</div>
)
]
} satisfies Meta<typeof Button>
export default meta
type Story = StoryObj<typeof meta>
export const Default: Story = {
args: {
children: 'Hello 🐼!'
}
}
Configuring Dark Mode
To enable dark mode in Storybook, you can use the @storybook/addon-themes
package.
pnpm add -D @storybook/addon-themes
Then, update your .storybook/preview.ts
file to include the following:
.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 '@pandacss/dev/postcss'
, update the
PostCSS config as follows:
postcss.config.js
module.exports = {
plugins: [require('@pandacss/dev/postcss')]
}
HMR not triggered
If you are having issues with HMR not being triggered after a panda.config.ts
change (or one of its
dependencies, you can manually specify the files that should trigger a rebuild
by adding the following to your panda.config.ts
:
panda.config.ts
import { defineConfig } from '@pandacss/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
like"./stories/**/*.{js,jsx,ts,tsx}"
- you didn't wrap your
args
object (or some part of it) with the.raw()
marker that helps Panda find style usage (opens in a new tab)
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
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
panda.config.ts
import { defineConfig } from '@pandacss/dev'
export default defineConfig({
// ...
staticCss: {
recipes: '*'
}
})