guides
static

Static CSS Generator

Bamboo can be used to generate a static set of utility classes for your project.

Bamboo can be used to generate a static set of utility classes for your project.

This is useful if you want to use Bamboo in an HTML project or you want absolute zero runtime.

Usage

To generate a static set of CSS classes, add them to your bamboo.config.js file:

export default {
  staticCss: {
    // the css properties you want to generate
    css: [],
    // the recipes you want to generate
    recipes: {},
    // the patterns you want to generate
    patterns: {},
    // the theme variants you want to generate
    themes: [],
  },
}

The staticCss property supports four properties:

  • css - an array of CSS rules you want to generate, each with their conditions
  • recipes - the component recipes you want to generate, or '*' for every recipe and every variant
  • patterns - the patterns you want to generate, keyed by pattern name
  • themes - the theme variants to include in the CSS output

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: an object mapping each CSS property to the array of values to generate for it. '*' stands for every value the tokens define; any other entry is generated as written.
  • conditions: the CSS conditions or selectors you want to generate in addition to the default values. Values can be light, dark, etc.
  • responsive: whether or not to generate responsive classes
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 '@bamboocss/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 '@bamboocss/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):

bamboo.config.ts

import { defineConfig } from '@bamboocss/dev'
 
export default defineConfig({
  // ...
  staticCss: {
    recipes: '*',
  },
})

This is mostly useful for testing purposes with Storybook.

Generating Patterns

The patterns property is an object of patterns, each taking the same rules as css. The properties are the pattern's own props rather than CSS properties, and '*' covers every prop the pattern declares.

export default {
  staticCss: {
    patterns: {
      flex: [{ properties: { gap: ['*'], align: ['center'] } }],
      // shorthand for every prop of the pattern
      center: ['*'],
    },
  },
}

Generating Themes

themes lists the theme variants to emit. No theme variant reaches the CSS output unless it is named here.

export default {
  staticCss: {
    themes: ['primary', 'secondary'],
  },
}

Performance Considerations

Pre-generating large numbers of styles costs build time and CSS size. 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.

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

Reach for prune first — it drops token declarations, @property registrations and keyframes the finished stylesheet cannot reach, and preflight.prune drops the parts of the reset that style elements you never render. These read the build's own output rather than guessing from your markup, so they are safe in ways a selector scan is not.

Note that staticCss works against them: every rule it emits is a rule the pruning has to keep, along with whatever it references. If you added a staticCss entry to stop a token category being pruned, use prune.keepTokens instead — it keeps the declarations without emitting a rule per value to hold them up.

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.