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:
pnpm create next-app@14 my-app --typescript --tailwind --eslint --app --no-src-dir --import-alias "@/*"
cd my-appPin TypeScript to 5.x — TypeScript 6 deprecates baseUrl, which the Next scaffold still uses:
pnpm add -D typescript@^5.4.0Installation
Install the component library, token package, and optionally the chart package:
pnpm add @haydywoo/dave-react @haydywoo/dave-tokens @haydywoo/dave-chartsSet up tokens
Import the token CSS file into your global stylesheet. This sets up all the CSS custom properties that components depend on:
/* 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:
// 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:
/** @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
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):
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):
// 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