Theming
Light and dark mode theming
The project supports light and dark themes using CSS variables and the next-themes library.
Theme System
Themes are controlled via the ThemeProvider in src/providers/theme-provider.tsx:
import { ThemeProvider } from "@/providers/theme-provider";
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
>
{children}
</ThemeProvider>Theme Configuration
Configure theme behavior in src/config/app.ts:
Config.Theme.DEFAULT = "system"; // "light" | "dark" | "system"
Config.Theme.ENABLE_SYSTEM = true; // Allow system theme detection
Config.Theme.FORCE = undefined; // Force specific theme (overrides user)Options
| Setting | Type | Description |
|---|---|---|
DEFAULT | "light" | "dark" | "system" | Default theme |
ENABLE_SYSTEM | boolean | Allow system preference |
FORCE | "light" | "dark" | Force theme (overrides user) |
Using Themes
Theme Switcher
Import the theme switcher component:
import { ThemeSwitcher } from "@/components/theme-switcher";
<ThemeSwitcher />This renders a dropdown with:
- Light mode
- Dark mode
- System preference (if enabled)
Programmatic Control
Use the useTheme hook:
"use client";
import { useTheme } from "next-themes";
function MyComponent() {
const { theme, setTheme, systemTheme } = useTheme();
return (
<div>
<p>Current theme: {theme}</p>
<button onClick={() => setTheme("light")}>Light</button>
<button onClick={() => setTheme("dark")}>Dark</button>
<button onClick={() => setTheme("system")}>System</button>
</div>
);
}CSS Variables
Theme colors are defined using CSS variables in src/styles/globals.css:
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
/* ... more variables */
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--primary: 217.2 91.2% 59.8%;
--primary-foreground: 222.2 47.4% 11.2%;
/* ... more variables */
}
}Variable Format
Variables use HSL format without the hsl() wrapper:
/* ✅ Correct */
--primary: 221.2 83.2% 53.3%;
/* ❌ Incorrect */
--primary: hsl(221.2, 83.2%, 53.3%);Styling for Themes
Use the dark: prefix for dark mode styles:
<div className="bg-white dark:bg-gray-900">
{/* White background in light mode, dark gray in dark mode */}
</div>
<p className="text-gray-900 dark:text-gray-100">
{/* Dark text in light mode, light text in dark mode */}
</p>Semantic Colors
Prefer semantic color tokens that adapt automatically:
// ✅ Good - automatically adapts to theme
<div className="bg-background text-foreground">
<div className="bg-primary text-primary-foreground">
// ❌ Avoid - requires manual dark: variants
<div className="bg-white dark:bg-black text-black dark:text-white">Color Customization
Modifying Theme Colors
Edit src/styles/globals.css to customize colors:
:root {
--primary: 221.2 83.2% 53.3%; /* Light mode primary */
}
.dark {
--primary: 217.2 91.2% 59.8%; /* Dark mode primary */
}Color Palette Generator
Use the Shadcn theme generator to create color palettes:
npx shadcn-ui@latest addOr visit: https://ui.shadcn.com/themes
Theme-Aware Components
Components automatically adapt using CSS variables:
import { Card } from "@/components/ui/card";
<Card>
{/* Automatically uses --card and --card-foreground */}
</Card>Available Theme Variables
| Variable | Purpose |
|---|---|
--background | Page background |
--foreground | Primary text |
--card | Card background |
--card-foreground | Card text |
--primary | Primary color |
--secondary | Secondary color |
--muted | Muted background |
--muted-foreground | Muted text |
--accent | Accent highlights |
--destructive | Destructive actions |
--border | Borders |
--input | Input backgrounds |
--ring | Focus rings |
Force Theme
To disable theme switching and force a specific theme:
// src/config/app.ts
Config.Theme.FORCE = "dark"; // Forces dark modeThis:
- Hides the theme switcher
- Ignores user preference
- Overrides system preference
Best Practices
- Use semantic colors - Use
bg-background,text-foregroundinstead of manual dark: variants - Test both themes - Always test components in light and dark mode
- Avoid hardcoded colors - Use CSS variables for automatic theme adaptation
- Respect system preference - Enable system theme by default for better UX
The theme is stored in localStorage and persists across sessions.