Theming
Learn how the color system works and how to customize the look and feel of Apex Dashboard.
OKLCh Color Tokens
All colors are defined as CSS custom properties using the OKLCh color space. OKLCh provides perceptually uniform lightness, making it easier to create consistent color palettes. The tokens are defined in src/app/globals.css.
:root {
--primary: oklch(0.55 0.175 160);
--primary-foreground: oklch(0.985 0.002 230);
--background: oklch(0.985 0.002 230);
--foreground: oklch(0.155 0.015 230);
--card: oklch(1 0 0);
--muted: oklch(0.96 0.005 230);
--muted-foreground: oklch(0.556 0.015 230);
--border: oklch(0.922 0.005 230);
/* ... more tokens */
}The OKLCh format is oklch(lightness chroma hue) where lightness is 0–1, chroma is 0–0.4, and hue is 0–360 degrees. Tailwind CSS v4 maps these tokens through the @theme inline block at the top of globals.css.
Changing the Primary Color
To change the primary color, update the --primary token in both the :root (light) and .dark blocks. For example, to switch from teal to blue:
/* Light mode */
:root {
--primary: oklch(0.55 0.175 250); /* hue 160 → 250 (blue) */
--primary-foreground: oklch(0.985 0.002 230);
--ring: oklch(0.55 0.175 250);
}
/* Dark mode */
.dark {
--primary: oklch(0.65 0.19 250);
--primary-foreground: oklch(0.09 0.015 170);
--ring: oklch(0.65 0.19 250);
}The change propagates everywhere bg-primary, text-primary, or ring-primary is used — buttons, links, active states, charts, and sidebar accents all update automatically.
Semantic Color Tokens
The design system uses semantic names rather than raw color values. Each token has a foreground counterpart for text that sits on top of it:
| Token | Purpose |
|---|---|
| --primary | Brand color, buttons, active states |
| --secondary | Secondary actions, subtle backgrounds |
| --muted | Muted backgrounds, code blocks |
| --accent | Hover states, highlights |
| --destructive | Error states, delete actions |
| --success | Success indicators, positive trends |
| --warning | Warning badges, caution states |
| --chart-1 to --chart-5 | Chart color palette (5 colors) |
| --sidebar-* | Sidebar-specific tokens (dark sidebar in light mode) |
Dark Mode
Dark mode is implemented by toggling a .dark class on the <html> element. The ThemeProvider component in src/components/theme-provider.tsx manages the state and persists the preference to localStorage. The Tailwind dark variant is configured in globals.css:
@custom-variant dark (&:is(.dark *));This allows you to use dark:bg-slate-900 classes in your components, and the .dark block in globals.css overrides all semantic tokens for dark mode.
Using the Theme Provider
The useTheme hook provides access to the current theme and a setter:
"use client";
import { useTheme } from "@/components/theme-provider";
export function MyComponent() {
const { theme, setTheme } = useTheme();
return (
<button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
Current theme: {theme}
</button>
);
}Supported values are "light", "dark", and "system". The system option follows the user's OS preference and reacts to changes in real time.
Next Steps
See Components for a full list of available UI primitives, or learn how to add new pages to the dashboard.