---
title: Using React Router
description: Easily use Bamboo with React Router with our dedicated integration.
---

## Start a new project

<Steps>

### Create project

To get started, we will need to create a new React Router project using the official
[Create React Router](https://reactrouter.com/start/framework/installation) CLI. In this guide, we will use TypeScript.

If you don't enter any parameter, the CLI will guide you through the process of creating a new React Router app.

<Tabs items={['pnpm', 'npm', 'yarn', 'bun']}>
  {/* <!-- prettier-ignore-start --> */}
  <Tab>
    ```bash
    pnpm dlx create-react-router@latest
    ```
  </Tab>
  <Tab>
    ```bash
    npx create-react-router@latest
    ```
  </Tab>
  <Tab>
    ```bash
    yarn dlx create-react-router@latest
    ```
  </Tab>
  <Tab>
    ```bash
    bunx create-react-router@latest
    ```
  </Tab>
  {/* <!-- prettier-ignore-end --> */}
</Tabs>

You will be asked a few questions, answer these as follows:

```sh
? Where should we create your new project? test-app
? Install dependencies? No
```

> **Note:** You should decline the dependency installation step as we will install dependencies together with Bamboo
> CSS.

### Install Bamboo

Install bamboo and create your `bamboo.config.ts` file. React Router 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.

<Tabs items={['pnpm', 'npm', 'yarn', 'bun']}>
  {/* <!-- prettier-ignore-start --> */}
  <Tab>
    ```bash
    pnpm install -D @bamboocss/dev @bamboocss/vite
    pnpm bamboo init
    ```
  </Tab>
  <Tab>
    ```bash
    npm install -D @bamboocss/dev @bamboocss/vite
    npx bamboo init
    ```
  </Tab>
  <Tab>
    ```bash
    yarn add -D @bamboocss/dev @bamboocss/vite
    yarn bamboo init
    ```
  </Tab>
  <Tab>
    ```bash
    bun add -D @bamboocss/dev @bamboocss/vite
    bun bamboo init
    ```
  </Tab>
  {/* <!-- prettier-ignore-end --> */}
</Tabs>

### Update package.json scripts

Add `"prepare": "bamboo codegen"` to `scripts`. It runs [codegen](/docs/references/cli#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 React Router 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. `./app/**/*` covers `app/root.tsx` as well as
everything under it.

```ts {5,8,11} filename="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: ['./app/**/*.{js,jsx,ts,tsx}'],

  // Files to exclude
  exclude: [],

  // The output directory for your css system
  outdir: 'styled-system',
})
```

### Replace Tailwind CSS with Bamboo CSS

Remove the Tailwind CSS plugin from `vite.config.ts` and add Bamboo's. The template's `app/app.css`, its import in
`app/root.tsx`, and any `links` entry pointing at it can go too — the next step imports Bamboo's stylesheet instead.

```ts {2,7} filename="vite.config.ts"
import { reactRouter } from '@react-router/dev/vite'
import bamboocss from '@bamboocss/vite'
import { defineConfig } from 'vite'
import tsconfigPaths from 'vite-tsconfig-paths'

export default defineConfig({
  plugins: [bamboocss(), reactRouter(), tsconfigPaths()],
})
```

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. You still need PostCSS for anything else you run through
it, autoprefixer included.

<Callout type="warning">
  Do not use `bamboo init --postcss` here. `@bamboocss/postcss` emits the stylesheet and nothing else — it does not
  compile source — so under it every `css()` and `cva()` call stays a runtime call and the generated style engine ships
  in your client bundle. Both setups render identically, which is what makes the difference easy to miss. See [Source
  compilation](/docs/guides/source-transformation).
</Callout>

### Import the virtual stylesheet

Import it once, from `app/root.tsx`:

```tsx {4} filename="app/root.tsx"
import { isRouteErrorResponse, Links, Meta, Outlet, Scripts, ScrollRestoration } from 'react-router'

import type { Route } from './+types/root'
import 'virtual:bamboo.css'

export function Layout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
        <Links />
      </head>
      <body>
        {children}
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  )
}
```

It 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 `app/vite-env.d.ts`, or add the second line to it if your template already has one, so TypeScript accepts that
import:

```ts filename="app/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

```tsx filename="app/routes/home.tsx"
import type { Route } from './+types/home'
import { css } from '../../styled-system/css'

export function meta({}: Route.MetaArgs) {
  return [{ title: 'New React Router App' }, { name: 'description', content: 'Welcome to React Router!' }]
}

export default function Home() {
  return (
    <div>
      <h1 className={css({ fontSize: '2xl', fontWeight: 'bold' })}>Welcome to the home page</h1>
    </div>
  )
}
```

</Steps>

## Troubleshooting

If your IDE does not autocomplete `styled-system` imports, add that directory to `include` in `tsconfig.json`, alongside
`app`. See [the CLI guide](/docs/installation/cli#troubleshooting).
