Theme System
All colors, fonts, spacing, and shadows live as CSS custom properties in src/app/globals.css. Changes propagate through every shadcn/ui component automatically.
Design tokens
The starter uses oklch for colors: it's perceptually uniform, meaning a lightness change looks equally bright across any hue. This matters when building accessible themes.
:root {
--background: oklch(0.97 0.01 87.41); /* warm cream */
--foreground: oklch(0.31 0.02 148.20); /* deep green-gray */
--primary: oklch(0.52 0.13 144.33); /* forest green */
--accent: oklch(0.90 0.05 146.01); /* pale sage */
/* ... */
}
Changing the primary color
Pick a color at oklch.com, then swap the three-number oklch in :root:
--primary: oklch(0.55 0.18 260); /* deep blue */
--primary-hover: oklch(0.50 0.18 260); /* primary minus ~0.05 L */
--ring: oklch(0.55 0.18 260); /* match primary */
Do the same in .dark for dark-mode values. Every button, link, badge, and focus ring will update.
Full token list
| Token | Purpose |
|---|---|
--background / --foreground | Page surface + primary text |
--card / --card-foreground | Card surfaces |
--primary / --primary-foreground | Buttons, CTAs, active links |
--secondary / --secondary-foreground | Secondary buttons, muted accents |
--muted / --muted-foreground | Subtle backgrounds + caption text |
--accent / --accent-foreground | Hover states, subtle highlights |
--destructive / --destructive-foreground | Delete, error |
--border / --input / --ring | Borders, form fields, focus rings |
--chart-1 … --chart-5 | Data visualization palette |
--sidebar-* | Sidebar-specific surfaces |
Dark mode
Dark mode is class-based (.dark on <html>) and managed by next-themes. The @variant dark (...) rule in globals.css lets Tailwind v4 toggle dark styles correctly.
import { useTheme } from "next-themes";
const { theme, setTheme } = useTheme();
setTheme("dark"); // or "light" or "system"
The <ThemeToggle /> component in src/components/theme/ is already wired in the header.
Typography
Fonts load via next/font/google in src/app/layout.tsx:
import { Montserrat, Merriweather, Source_Code_Pro } from "next/font/google";
Swap for any Google Font. Variable fonts are preferred for smaller bundle size.
The CSS variables are:
--font-sans: var(--font-montserrat), -apple-system, ...;
--font-serif: var(--font-merriweather), Georgia, serif;
--font-mono: var(--font-source-code-pro), ui-monospace, ...;
Change --font-montserrat → --font-your-new-sans in both layout.tsx (variable name) and globals.css (variable reference).
Spacing and radius
The starter uses an 8px grid (--space-1 = 4px through --space-24 = 96px) and a 0.5rem base border radius. Adjust in :root to change the feel of the whole app.
Shadows
Six shadow tokens (--shadow-2xs through --shadow-2xl) tuned for subtle depth. Override for a flatter or more dramatic look.
Next
- Content Authoring: write your first blog post
- Customization: branding, navigation, sections