Skip to content

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:

TokenPurpose
--primaryBrand color, buttons, active states
--secondarySecondary actions, subtle backgrounds
--mutedMuted backgrounds, code blocks
--accentHover states, highlights
--destructiveError states, delete actions
--successSuccess indicators, positive trends
--warningWarning badges, caution states
--chart-1 to --chart-5Chart 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.