Custom Themes

The theme system is built on CSS variables defined in globals.css. Both Tailwind utilities and shadcn/ui components reference these variables, so changing a few values updates the entire UI.

Theme variables

shadcn/ui expects a set of named CSS variables for colors, radii, and spacing. They live under :root for light mode and .dark for dark mode.

/* app/globals.css */
:root {
  --background: oklch(0.99 0.00 0);
  --foreground: oklch(0.13 0.00 0);
  --primary: oklch(0.55 0.18 260);
  --primary-foreground: oklch(0.98 0.00 0);
  --muted: oklch(0.95 0.01 260);
  --muted-foreground: oklch(0.50 0.02 260);
  --border: oklch(0.90 0.01 260);
  --radius: 0.5rem;
}

.dark {
  --background: oklch(0.13 0.02 260);
  --foreground: oklch(0.95 0.00 0);
  --primary: oklch(0.65 0.18 260);
  --primary-foreground: oklch(0.13 0.00 0);
  --muted: oklch(0.20 0.02 260);
  --muted-foreground: oklch(0.65 0.02 260);
  --border: oklch(0.25 0.02 260);
}

Using theme colors

Tailwind maps these variables to utility classes automatically:

<div className="bg-background text-foreground">
  <p className="text-muted-foreground">Subtle text</p>
  <button className="bg-primary text-primary-foreground">Action</button>
</div>

Dark mode

Dark mode is toggled by adding the .dark class to the <html> element. Use a theme provider component to manage the toggle.

import { ThemeProvider } from "next-themes";

export default function RootLayout({ children }) {
  return (
    <html suppressHydrationWarning>
      <body>
        <ThemeProvider attribute="class" defaultTheme="system">
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}

Creating a brand theme

To create a brand-specific theme, override the CSS variables with your brand palette.

VariableRoleExample (OKLCH)
--primaryMain brand coloroklch(0.60 0.22 145)
--primary-foregroundText on primaryoklch(0.98 0.00 0)
--accentSecondary brand coloroklch(0.70 0.14 200)
--destructiveError / danger actionsoklch(0.55 0.22 25)

OKLCH tips

  • Adjust L (lightness) to create lighter/darker shades of the same hue.
  • Keep C (chroma) under 0.25 for most UI surfaces; high chroma is best for accents.
  • Use a tool like oklch.com to pick values visually.