Tailwind CSS
Tailwind v4 + DaisyUI setup, oklch design tokens, and the GOaT design system.
The GOaT stack uses Tailwind CSS v4 with DaisyUI for component classes and oklch color tokens for a modern, dark-first design system.
Setup
styles/main.css:
@import "tailwindcss";
@plugin "daisyui";
Build with the Tailwind CLI:
npx @tailwindcss/cli -i styles/main.css -o static/styles.css --watch
Or for dev, use the CDN (no build step):
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<link href="https://cdn.jsdelivr.net/npm/daisyui@5/full.css" rel="stylesheet">
Dark-First Theme
Define your theme using DaisyUI’s @plugin syntax with oklch colors:
@plugin "daisyui/theme" {
name: "myapp-dark";
default: true;
prefersdark: true;
color-scheme: dark;
--color-base-100: oklch(14% 0.01 260);
--color-base-200: oklch(18% 0.012 260);
--color-base-300: oklch(23% 0.015 260);
--color-base-content: oklch(93% 0.008 260);
--color-primary: oklch(74% 0.19 45); /* Electric orange */
--color-primary-content: oklch(14% 0.01 45);
--color-accent: oklch(82% 0.14 85); /* Warm amber/gold */
--color-accent-content: oklch(20% 0.04 85);
--color-success: oklch(72% 0.17 155);
--color-error: oklch(65% 0.2 25);
--radius-box: 0.5rem;
--border: 1px;
--depth: 1;
}
Why oklch?
oklch is perceptually uniform — colors at the same lightness look the same lightness. This makes your design system predictable:
/* These all feel equally "vibrant" */
--color-primary: oklch(74% 0.19 45); /* Orange */
--color-success: oklch(72% 0.17 155); /* Green */
--color-error: oklch(65% 0.2 25); /* Red */
--color-info: oklch(70% 0.14 250); /* Blue */
Custom Components
Build reusable component classes that complement DaisyUI:
/* Frosted glass card */
.card-glass {
background: oklch(from var(--color-base-200) l c h / 0.6);
backdrop-filter: blur(12px) saturate(1.4);
border: 1px solid oklch(from var(--color-base-content) l c h / 0.08);
}
/* Gradient CTA button */
.btn-gradient {
background: linear-gradient(135deg, oklch(74% 0.19 45), oklch(78% 0.17 60));
color: oklch(14% 0.01 45);
border: none;
}
.btn-gradient:hover {
transform: translateY(-1px);
box-shadow: 0 4px 16px oklch(from var(--color-primary) l c h / 0.3);
}
/* Frosted glass nav */
.nav-glass {
background: oklch(from var(--color-base-100) l c h / 0.8);
backdrop-filter: blur(16px) saturate(1.5);
border-bottom: 1px solid oklch(from var(--color-base-content) l c h / 0.06);
}
Typography
Pair display and body fonts for visual hierarchy:
html {
font-family: 'Inter', system-ui, sans-serif;
}
h1, h2, h3, .font-display {
font-family: 'Clash Display', 'Inter', system-ui, sans-serif;
font-weight: 600;
letter-spacing: -0.02em;
}
.font-mono, code, pre {
font-family: 'JetBrains Mono', monospace;
}
/* Uppercase labels for sporting/data-dense UIs */
.label-uppercase {
text-transform: uppercase;
letter-spacing: 0.08em;
font-weight: 600;
font-size: 0.75rem;
}
Motion Tokens
Respect user preferences and keep animations consistent:
:root {
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
--ease-out-back: cubic-bezier(0.34, 1.56, 0.64, 1);
--duration-fast: 120ms;
--duration-base: 200ms;
}
@media (prefers-reduced-motion: reduce) {
:root {
--duration-fast: 0ms;
--duration-base: 0ms;
}
}
Gotchas
- Use the Tailwind CLI for production. CDN mode is fine for dev but doesn’t tree-shake.
- DaisyUI v5 uses
@pluginsyntax. Not the olddaisyui: { themes: [] }config. - oklch
fromsyntax (oklch(from var(--color-base-200) l c h / 0.6)) requires modern browsers. All evergreen browsers support it. - Don’t fight DaisyUI. Use its component classes (
btn,card,badge) and extend, don’t rebuild from scratch.