overview
why bamboo

Why Bamboo

From the endless list of CSS-in-JS libraries, why should you choose Bamboo?

Styles that resolve before they ship

Bamboo is a build-time CSS-in-JS engine. You write style objects; the Vite compiler resolves them into globally shared atoms and replaces every style-producing call with a literal or finite lookup. Open runtime styling is rejected. Nothing generates styles in the browser or injects them into the <head>.

Three things follow from that, and they are what Bamboo is for.

The call disappears

Every class name comes from a function call the compiler can see. There is no JSX factory, no template literal syntax and no style props, so the compiler can remove the call entirely:

// you write
export const title = css({ fontSize: 'lg', fontWeight: 'bold' })
 
// the bundle gets
export const title = 'fs_lg fw_bold'

A style that varies uses a declared, finite recipe axis. Bamboo precompiles every reachable StyleSet and leaves only a small decision table behind. An open value such as css({ color: tone }) is rejected because no finite stylesheet can back every value it might produce.

The payoff is larger than the CPU saved per call. Recipe configs and the style engine disappear from the production graph, while identical declarations from every recipe and css() call share one atom and one CSS rule.

A green build means a complete stylesheet

Static extraction's characteristic failure is silence. A file the parser threw on, a call to a pattern a preset dropped, a background: 'accent.default' naming a token that does not exist — each contributes no rule, and nothing downstream objects, because a stylesheet missing rules is still a valid stylesheet. The class the component asks for simply has nothing behind it, and it surfaces much later as "this colour never applied", a long way from the edit that caused it.

Bamboo treats that as a build failure rather than a fact of life:

ERR_BAMBOO_DEAD_IMPORT: 12 call(s) name a binding that does not exist:

`stack` is not a pattern — `../styled-system/patterns` does not export it.
  12 file(s): src/modal.tsx, src/drawer.tsx, src/sheet.tsx, … and 9 more

Build diagnostics lists what is checked, what each check costs, and which of them you can grade.

You ship what you use

The token layer declares every token in your theme while an app uses a fraction of them, so pruning what nothing can reach is usually the largest single saving in render-blocking CSS — 36% to 78% of styles.css on the example apps in this repository. The same applies to @keyframes a preset declares and your app never animates, and to the parts of the reset that style elements your source never renders.

Built at scale

Bamboo is the styling engine behind Contra (opens in a new tab), whose UI has more than 20,000 css() call sites. At that scale everything a styling library spends per call site – bytes emitted, work at runtime, time in the build – is multiplied by five figures, so optimizations too small to notice elsewhere are plainly measurable. Bamboo exists to chase them further than a general-purpose library reasonably would.

It began as a fork of Panda CSS (opens in a new tab) and keeps its authoring primitives: css, cva, sva, cx, patterns and recipes. The API is smaller and several behaviours differ — analyzable cx calls compose StyleSets, recipes share global atoms, and slot selections compile directly to per-slot atom strings — so if you are coming from Panda, read what changed before you migrate.

When to use Bamboo?

Bamboo suits an app whose stylesheet is starting to track the size of its design system rather than the size of its own UI, and a team that would rather have an extraction failure stop the build than find it in a diff of the output. It asks for something in return: styles are written one way, as objects passed to a call, and dynamic values have to be reachable statically or say so.

Styling engine

Bamboo integrates through Vite. Its compiler turns analyzable style calls into shared atomic CSS during the build, and fails when a class-producing call would survive to runtime.

import { css } from '../styled-system/css'
import { center, flex } from '../styled-system/patterns'
 
function App() {
  return (
    <div
      className={flex({
        direction: 'row',
        gap: '8px',
        p: '4',
        rounded: 'md',
        shadow: 'lg',
        bg: 'white',
      })}
    >
      <div className={center({ size: '5rem', borderRadius: 'full', overflow: 'hidden' })}>
        <img src="https://via.placeholder.com/150" alt="avatar" />
      </div>
      <div className={css({ mt: '4', fontSize: 'xl', fontWeight: 'semibold' })}>John Doe</div>
      <div className={css({ mt: '2', fontSize: 'sm', color: 'gray.600' })}>john@doe.com</div>
    </div>
  )
}

Token generator

Bamboo has first-class support for design tokens. It provides a way to express raw and semantic tokens for your project. The generator can be used to create a set of CSS variables for your design tokens.

bamboo.config.ts

export default defineConfig({
  emitTokensOnly: true,
  theme: {
    tokens: {
      colors: {
        gray50: { value: '#F9FAFB' },
        gray100: { value: '#F3F4F6' },
      },
    },
    semanticTokens: {
      colors: {
        primary: { value: 'token(colors.gray50)' },
        success: {
          value: { _light: 'token(colors.green500)', _dark: 'token(colors.green200)' },
        },
      },
    },
  },
})

Running the bamboo codegen will generate

styled-system/tokens/index.css

:where(:root, :host) {
  --colors-gray50: #f9fafb;
  --colors-gray100: #f3f4f6;
  --colors-primary: var(--colors-gray50);
}
 
.light {
  --colors-success: var(--colors-green500);
}
 
.dark {
  --colors-success: var(--colors-green200);
}

Then you have a set of css variables that you can use in your project.

@import '../styled-system/tokens/index.css';
 
.card {
  background-color: var(--colors-gray50);
}

When not to use Bamboo?

Bamboo isn't the right fit for your project if:

  • You're building with HTML and CSS.
  • You're using a template-based framework like PHP.
  • You're looking for an absolute zero JS solution.

In these scenarios, we recommend that you use vanilla CSS (which is getting awesome by the day), or other utility based CSS libraries.