Installation
Using Panda CSS with Storybook
Setting 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
:
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:
{
"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.
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:
@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.
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:
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>
)
};
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:
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:
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
:
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)
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
import { defineConfig } from "@pandacss/dev"
export default defineConfig({
// ...
staticCss: {
recipes: '*'
},
})