installation
tanstack start

Using TanStack Start

Easily use Bamboo with TanStack Start with our dedicated integration.

Start a new project

Create project

To get started, we will need to create a new TanStack Start project using the official TanStack CLI (opens in a new tab).

pnpm dlx @tanstack/cli@latest create

The CLI asks for a package manager and offers optional add-ons. Leave out Tailwind CSS: Bamboo takes its place.

Install Bamboo

Install bamboo and create your bamboo.config.ts file. TanStack Start builds with Vite, so this is the Vite integration — @bamboocss/vite is the compiler, and it is what keeps the style engine out of your client bundle.

pnpm install -D @bamboocss/dev @bamboocss/vite
pnpm bamboo init

Update package.json scripts

Add "prepare": "bamboo codegen" to scripts. It runs codegen after every dependency install, so the output directory can stay in .gitignore.

The build itself no longer needs it. The Vite plugin generates styled-system/ in buildStart, before anything resolves an import of it, so a fresh clone builds without a separate codegen step. Keep the script regardless: tsc and your editor read the generated types without ever running the plugin.

Configure the content

Make sure that all of the paths of your TanStack Start components are included in the include section of the bamboo.config.ts file.

This matters more under the compiler than it used to: a module it compiles that the extractor never read would have class names with no rules behind them, so the build fails instead. ./src/**/* covers src/router.tsx and every route under src/routes.

bamboo.config.ts

import { defineConfig } from '@bamboocss/dev'
 
export default defineConfig({
  // Whether to use css reset
  preflight: true,
 
  // Where to look for your css declarations
  include: ['./src/**/*.{js,jsx,ts,tsx}'],
 
  // Files to exclude
  exclude: [],
 
  // The output directory for your css system
  outdir: 'styled-system',
})

Add the plugin to your Vite config

Add Bamboo's plugin to vite.config.ts. If you created the project with the Tailwind CSS add-on, remove tailwindcss() here and the Tailwind import from src/styles.css.

vite.config.ts

import bamboocss from '@bamboocss/vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import viteReact from '@vitejs/plugin-react'
import { defineConfig } from 'vite'
 
export default defineConfig({
  resolve: { tsconfigPaths: true },
  plugins: [bamboocss(), tanstackStart(), viteReact()],
})

There is no postcss.config.cjs entry for Bamboo and no file carrying the @layer statement: the plugin serves the stylesheet as a virtual module that emits its own layer order.

Import the virtual stylesheet

Import it once, from the root route:

src/routes/__root.tsx

import { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router'
import 'virtual:bamboo.css'
 
export const Route = createRootRoute({
  head: () => ({
    meta: [{ charSet: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }],
  }),
  shellComponent: RootDocument,
})
 
function RootDocument({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <head>
        <HeadContent />
      </head>
      <body>
        {children}
        <Scripts />
      </body>
    </html>
  )
}

The root route is the place for it, because TanStack Start picks up a route's CSS imports by itself. The development server links them into the server-rendered page, so the first paint is already styled, and a production build links the emitted stylesheet the same way. Imported from src/router.tsx instead, the stylesheet still applies, but the development server does not collect it for server-rendered HTML, so pages render unstyled until the client hydrates.

The template links src/styles.css through a ?url import and a links entry instead. Bamboo's stylesheet can be linked the same way, with import bambooCss from 'virtual:bamboo.css?url' and { rel: 'stylesheet', href: bambooCss } in links, but that makes it an asset of its own rather than part of the CSS Vite bundles with the root route. Prefer the import above unless you need the URL itself.

It also has to be a JavaScript import. @import from a stylesheet does not reach it, because Vite resolves CSS @import before plugin resolution and the id names a virtual module this plugin resolves.

Create src/vite-env.d.ts, or add the second line to it if your project already has one, so TypeScript accepts that import:

src/vite-env.d.ts

/// <reference types="vite/client" />
/// <reference types="@bamboocss/vite/client" />

Start your build process

Start the dev server with pnpm dev.

Start using Bamboo

src/routes/index.tsx

import { createFileRoute } from '@tanstack/react-router'
import { css } from '../../styled-system/css'
 
export const Route = createFileRoute('/')({ component: Home })
 
function Home() {
  return <h1 className={css({ fontSize: '2xl', fontWeight: 'bold' })}>Hello šŸŽ‹!</h1>
}

Troubleshooting

If your IDE does not autocomplete styled-system imports, add that directory to include in tsconfig.json. See the CLI guide.