# Installation

> Add Roadie to a React app: packages, CSS, and fonts.

Set up Roadie in a React app.

## Install the packages

Install the core package and component library:

```bash
pnpm add @oztix/roadie-core @oztix/roadie-components
```

Add the others as you need them:

| Package                     | For                                                                                                                                                   |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `@oztix/roadie-charts`      | [Charts](https://ticketsolutionsptyltd.github.io/roadie/charts.md) and dashboards                                                                     |
| `@oztix/roadie-editor`      | The rich-text [Editor](https://ticketsolutionsptyltd.github.io/roadie/components/editor.md)                                                           |
| `@oztix/roadie-widgets`     | The cart drawer, in React or Vue                                                                                                                      |
| `@oztix/roadie-lint-plugin` | [Lint rules](https://ticketsolutionsptyltd.github.io/roadie/overview/linting.md) for oxlint or ESLint that catch Roadie mistakes, as a dev dependency |

## Setup

### 1. Add font preconnect hints

Add these to your HTML `<head>` to reduce font loading latency:

```html
<link rel="preconnect" href="https://assets.oztix.com.au" crossorigin />
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
```

### 2. Configure your CSS

In your main CSS entry point (such as `globals.css` or `index.css`), import Roadie's CSS. This single import includes Tailwind CSS v4, all design tokens, theme variables, and base styles:

```css
@import '@oztix/roadie-core/css';
```

### 3. Enable component class scanning

Tailwind v4 ignores `node_modules` by default, so it won't see the class strings inside Roadie's dist. If you're using `@oztix/roadie-components`, add one import. It ships its own `@source`, so you never write a `node_modules` path:

```css
@import '@oztix/roadie-core/css';
@import '@oztix/roadie-components/css';
```

Using widgets, charts, or the editor too? Add `@oztix/roadie-widgets/css`, `@oztix/roadie-charts/css`, or `@oztix/roadie-editor/css` as well. Each package's CSS registers only its own classes, so include every package you use. The React widget skins render Roadie components, so they need the components CSS too; the Vue skins don't:

```css
@import '@oztix/roadie-core/css';
@import '@oztix/roadie-components/css';
@import '@oztix/roadie-widgets/css';
@import '@oztix/roadie-charts/css';
@import '@oztix/roadie-editor/css';
```

### 4. Mount RoadieProvider

Wrap your app once, at the root. `RoadieProvider` routes every `href` through your router, handles light and dark, shows the [toasts](https://ticketsolutionsptyltd.github.io/roadie/components/toast.md) any component adds, and groups tooltips so a neighbour opens straight away.

```tsx
// app/providers.tsx
'use client'

import type { ReactNode } from 'react'

import NextLink from 'next/link'

import { RoadieProvider } from '@oztix/roadie-components'

export function Providers({ children }: { children: ReactNode }) {
  return <RoadieProvider link={NextLink}>{children}</RoadieProvider>
}
```

Render `<Providers>` around `{children}` in your root layout. The file is a client component because a Link component can't cross from the server, and your layout and pages stay server components. Each part takes its usual options, and `false` leaves that part out:

| Prop               | Sets up                                                                  | Leave it out               |
| ------------------ | ------------------------------------------------------------------------ | -------------------------- |
| `link`             | The Link component internal hrefs render through                         | Omit it for plain anchors  |
| `theme`            | `ThemeProvider` options, such as `followSystem` or `accentColor`         | `theme={false}`            |
| `toast`            | `Toast.Provider` options, plus the viewport's `position` and `container` | `toast={false}`            |
| `tooltip`          | `Tooltip.Provider` options, such as `delay`                              | `tooltip={false}`          |
| `direction`        | `ltr` or `rtl` for every component. Set `dir` on `<html>` to match       | Omit it to inherit         |
| `pendingIndicator` | The pending indicator on a `Navigator` frame                             | `pendingIndicator={false}` |

```tsx
<RoadieProvider
  link={NextLink}
  theme={{ followSystem: true }}
  toast={{ position: 'top-end', timeout: 6000 }}
>
  {children}
</RoadieProvider>
```

### Placing providers yourself

Every part is still exported on its own, and the nearest provider wins. This is what `RoadieProvider` mounts:

```tsx
'use client'

import type { ReactNode } from 'react'

import NextLink from 'next/link'

import { RoadieLinkProvider, ThemeProvider } from '@oztix/roadie-components'
import { Toast } from '@oztix/roadie-components/toast'
import { Tooltip } from '@oztix/roadie-components/tooltip'

export function Providers({ children }: { children: ReactNode }) {
  return (
    <RoadieLinkProvider Link={NextLink}>
      <ThemeProvider>
        <Tooltip.Provider>
          <Toast.Provider>
            {children}
            <Toast.Viewport />
          </Toast.Provider>
        </Tooltip.Provider>
      </ThemeProvider>
    </RoadieLinkProvider>
  )
}
```

Place them yourself when one root doesn't fit:

- **Widgets** in a page you don't own. Mount only what the widget uses, inside its own root, and leave the theme to the host page.
- **Scoped regions** that need something different, such as a collection route with its own accent (`<ThemeProvider accentColor={…}>`) or a panel with its own `Toast.Provider` and viewport.
- **Multiple React roots.** Context doesn't cross roots, so each root needs providers. Mount the theme in one root only, since it writes to the document, and give the others `<RoadieProvider theme={false} toast={false}>` or just the providers they use.

### Moving to RoadieProvider

Replace your root's `RoadieLinkProvider`, `ThemeProvider`, and `Toast.Provider` with one `RoadieProvider`, and move their props across: `Link` becomes `link`, the theme's props go in `theme`, and the toast provider's props and the viewport's `position` go in `toast`. Nothing else changes, and the individual providers keep working.

Keep an individual provider only for a deliberate scoped override. In development, Roadie warns when a `RoadieProvider` sits inside another one, or when a `ThemeProvider` or `Toast.Provider` it already mounts wraps it or sits straight inside it.

## Usage

### Using components

Import each component from its own subpath. Components use the `intent` and `emphasis` props for styling:

```tsx
import { Button } from '@oztix/roadie-components/button'

function MyComponent() {
  return (
    <div className='grid gap-4'>
      <h1 className='text-display-ui-3 text-strong'>Welcome</h1>
      <p className='text-subtle'>Get started with Roadie components.</p>
      <Button intent='accent' emphasis='strong'>
        Get started
      </Button>
    </div>
  )
}
```

### Using intent and emphasis

The `intent` prop sets a component's colour:

```tsx
<Button intent='neutral'>Default action</Button>
<Button intent='accent'>Primary action</Button>
<Button intent='danger'>Delete</Button>
<p className='intent-success'>Operation complete</p>
```

The `emphasis` prop controls the visual weight:

```tsx
<Button emphasis='strong'>Strong button</Button>
<Button emphasis='normal'>Normal button</Button>
<Button emphasis='subtle'>Subtle button</Button>
<p className='text-subtle'>Secondary text</p>
```

### Using Tailwind classes for layout

Use standard Tailwind CSS classes for layout, spacing, and custom styling:

```tsx
function MyComponent() {
  return (
    <div className='grid gap-4 p-4'>
      <div className='grid grid-cols-2 gap-2'>
        <div>Item 1</div>
        <div>Item 2</div>
      </div>
    </div>
  )
}
```

### Adding custom classes to components

All components accept a `className` prop for additional Tailwind classes:

```tsx
<Button className='w-full' intent='brand' emphasis='strong'>
  Full width button
</Button>
<p className='max-w-prose text-lg'>
  Constrained width text block.
</p>
```

## Building with AI

Each package ships a `roadie.manifest.json` that coding agents read, and a Claude Code plugin teaches agents to build with Roadie. [Building with AI](https://ticketsolutionsptyltd.github.io/roadie/overview/ai.md) covers both.

## Next steps

- Browse the [components](https://ticketsolutionsptyltd.github.io/roadie/components.md)
- Learn the [design tokens](https://ticketsolutionsptyltd.github.io/roadie/tokens/)
- Catch Roadie mistakes at lint time with the [lint plugin](https://ticketsolutionsptyltd.github.io/roadie/overview/linting.md)
- Set up Claude Code and other agents in [Building with AI](https://ticketsolutionsptyltd.github.io/roadie/overview/ai.md)

Docs updated 23 Oct 2026.
