Cheat Sheet
Every Bamboo API on one page.
Everything below is a function call that returns a class string. There is no JSX factory and no template literal syntax — one way to write a style, which is also what lets the build-time compiler resolve it completely.
Styling
import { css, cx } from '../styled-system/css'
css({ color: 'red.500', padding: '4' }) // tokens by name
css({ color: '#f00', padding: '13px' }) // raw values work too
css({ display: '[var(--btn-display)]' }) // escape hatch — skips token checking
css({ _hover: { color: 'red.700' } }) // condition as a block
css({ color: { base: 'red.500', _hover: 'red.700' } }) // …or per property
css({ fontSize: { base: 'sm', md: 'lg' } }) // responsive, mobile first
css({ color: { base: 'black', _dark: 'white' } }) // theming condition
cx('external', cond && 'another') // unknown external inputs remain a tiny runtime join
Composing styles
The compiler semantically composes statically analyzable Bamboo classes passed to cx. With unknown external inputs,
cx is only a string join and makes no conflict guarantee. Merge the objects when the inputs are available as
styles, where the last write wins per property:
css({ padding: '4' }, { padding: '8' }) // → padding 8
css(css.raw({ padding: '4' }), { padding: '8' }) // both objects are statically available
css.raw({ padding: '4' }) // a style object to merge later
See Merging styles.
Recipes
import { cva, sva } from '../styled-system/css'
const button = cva({
className: 'button', // optional extraction metadata; ignored by Vite atom identity
base: { borderRadius: 'md' },
variants: { size: { sm: { padding: '2' }, lg: { padding: '4' } } },
defaultVariants: { size: 'sm' },
compoundVariants: [{ size: 'lg', tone: 'brand', css: { fontWeight: 'bold' } }],
})
button({ size: 'lg' }) // shared atoms for this complete selection
const [variantProps, rest] = button.splitVariantProps(props)
The Vite compiler resolves the selected recipe and any statically analyzable cx() composition before allocating
globally shared atoms in utilities. Declaring the same shape in theme.recipes generates only reachable finite
variant states — see inline vs config recipes.
sva is the same for multi-part components. Under Vite, each selected slot receives its complete atom string:
const checkbox = sva({ slots: ['root', 'control'] /* … */ })
const classes = checkbox({ size: 'md' })
classes.root // shared atoms for the selected root styles
classes.control // shared atoms for the selected control styles
scopeRoots remains accepted as recipe metadata for compatibility, but compiled slot selections do not emit @scope.
Patterns
Layout helpers that are css() with a transform applied. flex, grid, gridItem, center, container, spacer,
divider, float, aspectRatio, bleed, linkOverlay.
import { flex } from '../styled-system/patterns'
;<div className={flex({ direction: 'column', gap: '4', align: 'center' })} />
Tokens and escape hatches
import { token } from '../styled-system/tokens'
import { css, fallback, viewTransition } from '../styled-system/css'
token('colors.red.500') // var(--colors-red-500)
token.value('colors.red.500') // the resolved value, for canvas and the like
css({ height: fallback('100dvh', '100vh') }) // progressive enhancement
viewTransition({
/* … */
}) // ::view-transition-* rules, one class
See Writing styles for the full surface.