Static CSS Generator
Panda can be used to generate a static set of utility classes for your project.
Panda can be used to generate a static set of utility classes for your project.
This is useful if you want to use Panda in an HTML project or you want absolute zero runtime.
Usage
To generate a static set of CSS classes, add them to your panda.config.js file:
export default {
staticCss: {
// the css properties you want to generate
css: [],
// the recipes you want to generate
recipes: {}
}
}
The static property supports two properties:
css- an array of CSS properties you want to generate with theirconditionsrecipes- the component recipes you want to generate
Generating CSS Properties
The css property is an array of CSS properties you want to generate with their conditions.
You can specify the following options:
properties: the CSS properties you want to generateconditions: the CSS conditions or selectors you want to generate in addition to the default values. Values can belight, dark, etc.responsive: whether or not to generate responsive classesvalues: the values you want to generate for the CSS property. When set to*, all values defined in the tokens will be included. When set to an array, only the values in the array will be generated.
export default {
staticCss: {
css: [
{
properties: {
margin: ['*'],
padding: ['*', '50px', '80px']
},
responsive: true
},
{
properties: {
color: ['*'],
backgroundColor: ['green.200', 'red.400']
},
conditions: ['light', 'dark']
}
]
}
}
Generating Recipes
The recipes property is an object of component recipes you want to generate with their conditions.
export default {
staticCss: {
recipes: {
button: [
{
size: ['sm', 'md'],
responsive: true
},
{ variant: ['*'] }
],
// shorthand for all variants
tooltip: ['*']
}
}
}
You can also directly specify a recipe's staticCss rules from inside a recipe config, e.g.:
import { defineRecipe } from '@pandacss/dev'
const card = defineRecipe({
className: 'card',
base: { color: 'white' },
variants: {
size: {
small: { fontSize: '14px' },
large: { fontSize: '18px' }
}
},
staticCss: [{ size: ['*'] }]
})
would be the equivalent of defining it inside the main config:
import { defineConfig } from '@pandacss/dev'
export default defineConfig({
// ...
staticCss: {
recipes: {
card: {
size: ['*']
}
}
}
})
Or you could even generate the CSS for every config recipe / slotRecipes (and each of their variants):
panda.config.ts
import { defineConfig } from '@pandacss/dev'
export default defineConfig({
// ...
staticCss: {
recipes: '*'
}
})This is mostly useful for testing purposes with Storybook.
Performance Considerations
Panda provides intelligent caching and memoization to optimize static CSS generation. However, pre-generating large numbers of styles can still impact build times. It's important to be selective and only generate the styles you actually need.
Best Practices
❌ Avoid: Generating every possible combination
export default {
staticCss: {
css: [
{
conditions: ['hover', 'focus', 'active', 'disabled'],
properties: {
// This expands to ALL tokens - very expensive!
color: ['*'],
backgroundColor: ['*'],
borderColor: ['*'],
width: ['*'],
height: ['*']
// ... 20+ more properties with wildcards
}
}
]
}
}
✅ Better: Only generate what you need
export default {
staticCss: {
css: [
{
conditions: ['_hover', '_focus'],
properties: {
// Only the colors you actually use
color: ['red.500', 'blue.500', 'gray.600'],
backgroundColor: ['white', 'gray.50', 'blue.50'],
borderColor: ['gray.200', 'blue.500']
}
}
]
}
}
When to Use Wildcards
Wildcards (['*']) are appropriate when:
- Small token sets: Properties with < 20 values (e.g.,
fontWeight: ['*']) - Critical utilities: Styles you genuinely need in all variants
- Testing scenarios: Storybook or visual regression testing
Use Responsive Selectively
The responsive property multiplies the number of generated classes by your breakpoints. Only enable it for properties
that genuinely need responsive behavior.
❌ Avoid: Responsive for all properties
export default {
staticCss: {
css: [
{
// This generates classes for ALL breakpoints (sm, md, lg, xl, 2xl)
responsive: true,
properties: {
color: ['red.500', 'blue.500'],
backgroundColor: ['white', 'gray.50'],
fontWeight: ['400', '500', '600'],
borderRadius: ['sm', 'md', 'lg']
}
}
]
}
}
✅ Better: Responsive only for layout properties
export default {
staticCss: {
css: [
{
// Responsive for layout properties that change across breakpoints
responsive: true,
properties: {
display: ['none', 'block', 'flex'],
flexDirection: ['row', 'column'],
width: ['full', '1/2', '1/3']
}
},
{
// No responsive needed for colors/typography that stay the same
properties: {
color: ['red.500', 'blue.500'],
fontWeight: ['400', '500', '600']
}
}
]
}
}
Properties that commonly need responsive: true:
- Layout:
display,flexDirection,gridTemplateColumns - Sizing:
width,height,maxWidth - Spacing:
padding,margin,gap - Positioning:
position,top,left
Properties that rarely need responsive: true:
- Colors:
color,backgroundColor,borderColor - Typography:
fontWeight,textDecoration,fontFamily - Effects:
boxShadow,opacity,cursor
Removing unused CSS
For an even smaller css output size, you can utilize PurgeCSS (opens in a new tab) to treeshake and remove unused CSS. This tool will analyze your template and match selectors against your CSS.