Getting started

DAVE is a React component library built on Tailwind CSS. Components are unstyled at the Tailwind level — they use semantic CSS custom properties, so you can theme the entire system by overriding a handful of variables.

Fair warning — DAVE is a personal design system, built for my own projects first. It's MIT licensed and free to use, but there's no stability guarantee, no versioning promise, and no support line. Things change when I need them to. Use it, fork it, adapt it — just go in with eyes open.

Prerequisites

DAVE targets Next.js 14 App Router (other React frameworks work but aren't tested). Start from a fresh create-next-app scaffold with TypeScript and Tailwind enabled:

Bash
pnpm create next-app@14 my-app --typescript --tailwind --eslint --app --no-src-dir --import-alias "@/*"
cd my-app

Pin TypeScript to 5.x — TypeScript 6 deprecates baseUrl, which the Next scaffold still uses:

Bash
pnpm add -D typescript@^5.4.0

Installation

Install the component library, token package, and optionally the chart package:

Bash
pnpm add @haydywoo/dave-react @haydywoo/dave-tokens @haydywoo/dave-charts

Set up tokens

Import the token CSS file into your global stylesheet. This sets up all the CSS custom properties that components depend on:

CSS
/* globals.css */
@import '@haydywoo/dave-tokens/dist/tokens.css';
 
@tailwind base;
@tailwind components;
@tailwind utilities;

Configure Next.js

Add transpilePackages so Next transpiles DAVE's ESM/CJS output consistently:

JavaScript
// next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
  transpilePackages: ['@haydywoo/dave-react', '@haydywoo/dave-charts', 'recharts'],
};
 
export default nextConfig;

Configure Tailwind

Add the complete semantic colour map, font families, and shadow tokens to your tailwind.config.js. The content array must include DAVE's compiled output so Tailwind's JIT generates the classes used inside the library:

JavaScript
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './app/**/*.{ts,tsx}',
    './node_modules/@haydywoo/dave-react/dist/**/*.js',
    './node_modules/@haydywoo/dave-charts/dist/**/*.js',
  ],
  theme: {
    extend: {
      fontFamily: {
        display: ['var(--font-display)', 'sans-serif'],
        body:    ['var(--font-body)',    'sans-serif'],
        code:    ['var(--font-code)',    'monospace'],
      },
      colors: {
        background:     'var(--color-background)',
        surface:        'var(--color-surface)',
        card:           'var(--color-card)',
        raised:         'var(--color-raised)',
        foreground:     'var(--color-foreground)',
        'fg-secondary': 'var(--color-foreground-secondary)',
        'fg-subdued':   'var(--color-foreground-subdued)',
        'fg-disabled':  'var(--color-foreground-disabled)',
        border: {
          DEFAULT: 'var(--color-border)',
          strong:  'var(--color-border-strong)',
        },
        accent: {
          DEFAULT:         'var(--color-accent)',
          hover:           'var(--color-accent-hover)',
          subtle:          'var(--color-accent-subtle)',
          'subtle-border': 'var(--color-accent-subtle-border)',
          border:          'var(--color-accent-border)',
          foreground:      'var(--color-accent-foreground)',
          on:              'var(--color-on-accent)',
        },
        success: {
          subtle:     'var(--color-success-subtle)',
          border:     'var(--color-success-border)',
          DEFAULT:    'var(--color-success)',
          foreground: 'var(--color-success-foreground)',
        },
        warning: {
          subtle:     'var(--color-warning-subtle)',
          border:     'var(--color-warning-border)',
          DEFAULT:    'var(--color-warning)',
          foreground: 'var(--color-warning-foreground)',
        },
        error: {
          subtle:     'var(--color-error-subtle)',
          border:     'var(--color-error-border)',
          DEFAULT:    'var(--color-error)',
          hover:      'var(--color-error-hover)',
          foreground: 'var(--color-error-foreground)',
        },
        chart: {
          1: 'var(--color-chart-1)', 2: 'var(--color-chart-2)',
          3: 'var(--color-chart-3)', 4: 'var(--color-chart-4)',
          5: 'var(--color-chart-5)', 6: 'var(--color-chart-6)',
          7: 'var(--color-chart-7)', 8: 'var(--color-chart-8)',
        },
      },
      boxShadow: {
        card:   'var(--shadow-card)',
        raised: 'var(--shadow-raised)',
      },
    },
  },
};

Use a component

TSX
import { Button, Card, CardHeader, CardTitle, CardContent } from '@haydywoo/dave-react';
 
export default function Page() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Hello</CardTitle>
      </CardHeader>
      <CardContent>
        <Button variant="primary">Get started</Button>
      </CardContent>
    </Card>
  );
}

Use a chart

Charts use index (the key for the x-axis category) and categories (an array of keys to plot as series):

TSX
import { BarChart } from '@haydywoo/dave-charts';
 
const data = [
  { month: 'Jan', sales: 42, refunds: 6 },
  { month: 'Feb', sales: 51, refunds: 4 },
  { month: 'Mar', sales: 48, refunds: 9 },
];
 
<BarChart
  data={data}
  index="month"
  categories={['sales', 'refunds']}
  height={240}
/>

TypeScript: CSS side-effect imports

If your pnpm build complains about a side-effect import for globals.css:

Type error: Cannot find module or type declarations for side-effect import of './globals.css'.

Add a global.d.ts at the project root (not next-env.d.ts — Next regenerates that file on every build and strips additions):

TypeScript
// global.d.ts
declare module '*.css';

What's next

  • Theming — swap the accent colour for your brand
  • Colours — the full token scale
  • Components — browse the component library