Skip to content
OTFotf

Components for @otfdashkit/ui

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

@otfdashkit/ui is the web side of the OTF design system. The shared catalog contains 108 installable components (89 web + 19 React Native). Blocks and patterns are listed in their own catalogs. Web components are grouped into four buckets, all built on Radix UI + Tailwind and styled via the shared @otfdashkit/tokens CSS variables.

Buckets

BucketWhat's thereWhen to reach for it
PrimitivesUnstyled-but-themed building blocks (Button, Input, Dialog, Tabs, …)You're composing your own UI
CompositeOpinionated pieces (Persona, Stat, Banner, DataGrid, …)You want a finished pattern, not a Lego brick
BlocksProduct-shape blocks — sidebars, modals, dashboard layoutsYou're standing up a new app screen and want a working starting point
AdvancedPower-user pieces — Kanban, Gantt, Rich Editor, Command Bar, Filters, Bulk ActionsYou're building an internal-tool-grade interface

Importing

Every export sits at the package root:

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>:

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

See Tokens / Themes 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:

<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:

<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:

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.

Need more than components?

Full-stack kits.
Pay once, own the code.

Auth, database, and payments already connected — so you ship product, not setup. Or take the delivered kits in the Bundle.

Everything Bundle — $149See full pricing

Get the free AI configs pack

Pre-tuned AI configs for Cursor, Claude, and Lovable — drop them in and your AI tool instantly understands your project.

No spam. Unsubscribe any time.

Prefer the free SDK? Star it on GitHub →