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 theirconditions
recipes
- 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.