# Overview

> The @otfdashkit/ui component surface — primitives, composites, blocks, and advanced.

`@otfdashkit/ui` is the web side of the OTF design system. It bundles **~85 components** in
four buckets, all built on Radix UI + Tailwind and styled via the shared `@otfdashkit/tokens`
CSS variables.

## Buckets

| Bucket                                    | What's there                                                                          | When to reach for it                                                                          |
| ----------------------------------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| **[Primitives](/docs/components/ui/primitives)** | 50 unstyled-but-themed building blocks (Button, Input, Dialog, Tabs, …)              | You're composing your own UI                                                                  |
| **[Composite](/docs/components/ui/composite)**   | 16 opinionated pieces (Persona, Stat, Banner, DataGrid, …)                            | You want a finished pattern, not a Lego brick                                                  |
| **[Blocks](/docs/components/ui/blocks)**         | ~25 product-shape blocks — sidebars, modals, dashboard layouts                         | You're standing up a new app screen and want a working starting point                         |
| **[Advanced](/docs/components/ui/advanced)**     | 7 power-user pieces — Kanban, Gantt, Rich Editor, Command Bar, Filters, Bulk Actions   | You're building an internal-tool-grade interface                                              |

## Importing

Every export sits at the package root:

```tsx
import {
  Button,
  Input,
  Dialog, DialogContent, DialogTitle,
  Stat,
  Persona,
  CommandBar,
} from '@otfdashkit/ui'
```

There's no submodule split (e.g. `@otfdashkit/ui/blocks`) — the bundler tree-shakes unused
exports just fine, and a single import surface is what AI tools handle best when they
write code against your kit.

## Theming

Every component reads its colors from the tokens published by `@otfdashkit/tokens`. To switch
themes at runtime, swap the class on `<html>`:

```ts
document.documentElement.className = 'theme-warm dark'
```

See [Tokens / Themes](/docs/tokens/overview) for the four shipped themes (`theme-slate`,
`theme-warm`, `theme-cosmic`, `theme-terminal`) and how to author your own.

## Charts

`Chart`, `BarChart`, `LineChart`, `AreaChart`, `BarList`, `Sparkline`, `Heatmap`, and
`ActivityHeatmap` all live in `@otfdashkit/ui` and consume the same chart tokens. **Always
pass theme tokens for colors:**

```tsx
<BarChart
  data={data}
  dataKey={['issues', 'completed']}
  colors={['hsl(var(--chart-1))', 'hsl(var(--chart-3))']}
  stacked
/>
```

When passing data to recharts-backed charts, **deep-clone first** — recharts mutates the array,
and Storybook's frozen args throw:

```tsx
<BarChart data={data.map((d) => ({ ...d }))} ... />
```

## Toasts

Toasts ship inside `@otfdashkit/ui/styles`. To render them, mount `<Toaster />` once at
the root of your app and call `toast(...)` imperatively from anywhere:

```tsx
import { Toaster, toast } from '@otfdashkit/ui'

export default function RootLayout({ children }) {
  return (
    <>
      {children}
      <Toaster />
    </>
  )
}
```

## A11y + linting

`@otfdashkit/eslint-plugin-otf-design` ships rules that catch:

- Hardcoded hex / RGB outside `lib/theme.ts`
- Inline `style={{ background: '...' }}`
- Missing `data-slot` attributes on custom components

Add it to your ESLint config and your kit will inherit the same conventions the OTF kits
themselves are linted against.

## What's NOT in the box

Some pieces are deliberately not shipped:

- **Charts library**. We re-export recharts wrappers, not a custom charting engine.
- **Form library**. `Form`, `FormField` are thin Radix primitives; bring your own
  resolver (zod / valibot / yup) via `@hookform/resolvers`.
- **Date library**. `Calendar` is a wrapper around `react-day-picker`; format dates with
  whatever you already use.
- **State management**. The blocks accept controlled props; pick TanStack Query / Zustand /
  Redux yourself.

This keeps the bundle small and the API surface honest.
