Migrating from Stitches
Migrate your project from Stitches to Bamboo.
This guide helps you migrate from Stitches to Bamboo and understand the design differences between the libraries.
Disclaimer: This isn't about comparing which one is best. Bamboo and Stitches are two different CSS-in-JS solutions with design decisions.
Here are some similarities between the two libraries.
- Bamboo uses the object literal syntax to define styles. It also supports the shorthand syntax for the
marginandpaddingproperties. - Bamboo supports the
variants,defaultVariantsandcompoundVariantsAPIs. - Bamboo supports design tokens and themes.
- Bamboo supports all the variants of nested selectors (attribute, class, pseudo, descendant, child, sibling selectors
and more). It also requires the use of the
&to chain selectors.
Below are some of the differences between the two libraries.
css function
In Stitches, the css function is used to author both regular style objects and variant style objects.
import { css } from '@stitches/react'
// definition
const styles = css({
border: 'solid 1px red',
backgroundColor: 'transparent',
variants: {
variant: {
// ...
}
}
})
// usage
<button className={styles({ variant: 'primary' })} />
In Bamboo, the css function is only used to author atomic styles, and the cva function to create variant style
objects.
The css function
import { css } from '../styled-system/css'
// definition
const styles = css({
border: 'solid 1px red',
backgroundColor: 'transparent'
})
// usage
<button className={styles} />
The cva function
import { cva } from '../styled-system/css'
// definition
const styles = cva({
base: {
border: 'solid 1px red',
backgroundColor: 'transparent'
},
variants: {
variant: {
// ...
}
}
})
// usage
<button className={styles({ variant: 'primary' })} />
styled function
In Stitches, the styled function creates components bound to both regular and variant style objects, and generates a
unique className for each variant.
import { styled } from '@stitches/react'
const Button = styled('button', {
// base styles
backgroundColor: 'gainsboro',
borderRadius: '9999px',
variants: {
// variant styles
},
})
// => <button class="c-coNKBW c-coNKBW-dnSdJM-variant-primary">Button</button>
Bamboo has no styled factory. Base styles go under the base key of a recipe. With Vite, inline and configured
recipes compile into the same globally shared atom pool; the choice is about organization and generated API, not CSS
identity.
- Colocated with the component, using the
cvafunction. Static selections compile directly; finite runtime axes compile to reduced decision tables containing only complete reachable style sets.
import { cva } from '../styled-system/css'
const button = cva({
className: 'button',
base: {
backgroundColor: 'gainsboro',
borderRadius: '9999px',
},
})
// => <button class="button">Button</button>
className is optional extraction metadata. It does not enter Vite's declaration identity or the names of the atoms it
emits.
- In the config, by defining the recipe in
bamboo.config.ts. It uses the same Vite lowering as an inline recipe, while codegen exposes a named import and its variant types.
import { defineConfig, defineRecipe } from '@bamboocss/dev'
const buttonStyle = defineRecipe({
className: 'button',
base: {
backgroundColor: 'gainsboro',
borderRadius: '9999px',
},
variants: {
// variant styles
},
})
export default defineConfig({
theme: {
extend: {
recipes: {
buttonStyle,
},
},
},
})
You might need to run bamboo codegen --clean to generate the recipe functions.
import { buttonStyle } from '../styled-system/recipes'
;<button className={buttonStyle({ variant: 'primary' })}>Button</button>
// => <button className="button button--variant_primary">Button</button>
Responsive Styles
In Stitches, you configure breakpoints in the media key of the createStitches method, and use it via the
@<breakpoint> syntax.
import { createStitches } from '@stitches/react'
// configure
const { styled, css } = createStitches({
media: {
bp1: '(min-width: 640px)',
bp2: '(min-width: 768px)',
},
})
// usage
const styles = css({
backgroundColor: 'gainsboro',
'@bp1': {
backgroundColor: 'tomato',
},
})
In Bamboo, you configure breakpoints in the theme.breakpoints key of the bamboo.config function
import { defineConfig } from '@bamboocss/dev'
export default defineConfig({
theme: {
extend: {
breakpoints: {
bp1: '640px',
bp2: '768px',
},
},
},
})
// usage
import { css } from '../styled-system/css'
const styles = css({
bg: 'gainsboro',
bp1: { bg: 'tomato' },
// or
margin: { base: '10px', bp1: '20px' },
})
In Stitches, you use the @initial keyword to target the base styles.
In Bamboo, you use the base key to target the base styles.
Tokens and Theme
Tokens
In Stitches, tokens are defined in the theme key of the createStitches method.
import { createStitches } from '@stitches/react'
const { styled, css } = createStitches({
theme: {
colors: {
gray100: 'hsl(206,22%,99%)',
gray200: 'hsl(206,12%,97%)',
},
},
space: {},
fonts: {},
})
// usage
const styles = css({
backgroundColor: '$gray100',
})
In Bamboo, tokens are defined in the theme key of the bamboo.config function.
import { defineConfig } from '@bamboocss/dev'
export default defineConfig({
theme: {
tokens: {
colors: {
gray100: { value: 'hsl(206,22%,99%)' },
gray200: { value: 'hsl(206,12%,97%)' },
},
spacing: {},
fonts: {},
},
semanticTokens: {
// ...
},
},
})
// usage
import { css } from '../styled-system/css'
const styles = css({
backgroundColor: 'gray100',
})
Notice that in Bamboo, you don't need to use the $ prefix to access the tokens. If you want to keep it across the
board, format the token names in a hook rather than renaming every token:
import { defineConfig } from '@bamboocss/dev'
export default defineConfig({
// ...
plugins: [
{
name: 'stitches-token-names',
hooks: {
'tokens:created': ({ configure }) => {
configure({
formatTokenName: (path) => '$' + path.join('-'),
})
},
},
},
],
})
Themes
In Stitches, the createTheme function is used to define dark theme values.
import { createStitches } from '@stitches/react'
const { createTheme } = createStitches({})
// create theme
const darkTheme = createTheme({
colors: {
gray100: 'hsl(206,8%,12%)',
gray200: 'hsl(206,7%,14%)'
}
})
// apply theme
<div className={darkTheme}>
<div>Content nested in dark theme.</div>
</div>
In Bamboo, themes are designed as semantic tokens. You can define the semantic tokens in the semanticTokens key of the
bamboo.config function.
import { defineConfig } from '@bamboocss/dev'
export default defineConfig({
theme: {
semanticTokens: {
colors: {
gray100: {
value: { base: 'hsl(206,22%,99%)', _dark: 'hsl(206,8%,12%)' },
},
gray200: {
value: { base: 'hsl(206,12%,97%)', _dark: 'hsl(206,7%,14%)' },
},
},
},
},
})
Token Aliases
In Stitches, you can create locally scoped tokens using the $$ prefix
import { styled } from '@stitches/react'
const Button = styled('button', {
$$shadowColor: '$colors$pink500',
boxShadow: '0 0 0 15px $$shadowColor',
})
In Bamboo, there's no special syntax, you need to use the css variable syntax. CSS variables are able to query the theme tokens directly using dot notation
import { css } from '../styled-system/css'
const button = css({
'--shadowColor': 'colors.pink500',
boxShadow: '0 0 0 15px var(--shadowColor)',
})
Animations
In Stitches, you can define keyframes using the keyframes method.
import { keyframes, styled } from '@stitches/react'
const scaleUp = keyframes({
'0%': { transform: 'scale(1)' },
'100%': { transform: 'scale(1.5)' },
})
// usage
const Button = styled('button', {
'&:hover': {
animation: `${scaleUp} 200ms`,
},
})
In Bamboo, you define keyframes in the theme.keyframes key of the bamboo.config function.
import { defineConfig } from '@bamboocss/dev'
export default defineConfig({
theme: {
extend: {
keyframes: {
scaleUp: {
'0%': { transform: 'scale(1)' },
'100%': { transform: 'scale(1.5)' },
},
},
},
},
})
// usage
import { css } from '../styled-system/css'
const style = css({
'&:hover': {
animation: 'scaleUp 200ms',
},
})
Utils
In Stitches, you can define utilities by using the utils key in the createStitches method.
import { createStitches, type PropertyValue } from '@stitches/react'
const { styled, css } = createStitches({
utils: {
linearGradient: (value: PropertyValue<'backgroundImage'>) => ({
backgroundImage: `linear-gradient(${value})`,
}),
},
})
In Bamboo, you get a lot of built-in utilities (like mx, marginX, my, py, etc.) that you can use out of the box. You can
also create custom utilites using the utilities key in the bamboo.config function.
The utilities API allows you define the connected token scale, generated className, and transform function.
import { defineConfig } from '@bamboocss/dev'
export default defineConfig({
utilities: {
extend: {
linearGradient: {
// (optional): the css property this maps to (to inherit the types from)
property: 'backgroundImage',
// (optional): the className to generate
className: 'bg_gradient',
// (optional): the shorthand name to use in the css
shorthand: 'gradient',
// (required): maps the value to the raw css object
transform: (value) => ({
backgroundImage: `linear-gradient(${value})`,
}),
},
},
},
})
Running bamboo codegen will update the typings for the utilities, allowing for a type-safe developer experience.
Then you can use the utility in your styles.
import { css } from '../styled-system/css'
const buttonClass = css({
linearGradient: '19deg, #21D4FD 0%, #B721FF 100%',
})
Global Styles
In Stitches, you define the global styles using the global.css function, and then call it in your app.
import { globalCss } from '@stitches/react'
const globalStyles = globalCss({
'*': { margin: 0, padding: 0 },
})
// then in your app
globalStyles()
In Bamboo, you define the global styles in the bamboo.config.ts under global.css, using the defineGlobalStyles
helper.
The styles are emitted automatically under the base cascade layer by the Vite plugin
import { defineConfig, defineGlobalStyles } from '@bamboocss/dev'
const globalCss = defineGlobalStyles({
'*': { margin: 0, padding: 0 },
})
export default defineConfig({
// ...
global: { css: globalCss },
})
Targeting Components
In Stitches, you can directly target React or styled components via the toString() method.
import { css } from '@stitches/react'
const Icon = () => (
<svg className="right-arrow" ... />
);
// add a `toString` method
Icon.toString = () => '.right-arrow';
const buttonClass = css({
[`& ${Icon}`]: {
marginLeft: '5px'
}
})
In Bamboo, you need to use the native selector directly. This is largely due to the static nature of Bamboo
import { css } from '../styled-system/css'
const Icon = () => (
<svg className="right-arrow" ... />
);
const buttonClass = css({
"& .right-arrow": {
marginLeft: '5px'
}
})
Server Side Rendering
Stitches needs per-framework SSR wiring — getCssText() from createStitches, and its output placed into the document
head by hand.
Bamboo needs none of it. Styles are extracted and emitted at build time by the Vite plugin, so there is nothing to collect at request time.
Conclusion
Before choosing your preferred CSS-in-JS library, be sure to consider your engineering and design goals. Both Stitches and Bamboo are capable of achieving many of the same styling goals, but they have different approaches.