Theme System (Dark/Light Mode)
Build a theme system with CSS variables and next-themes for dark/light mode
The theme system uses CSS variables for flexibility and next-themes for seamless dark/light mode switching. CSS variables allow instant theme changes without re-rendering components — just swap the variable values. next-themes handles system preference detection, persistence in localStorage, and prevents the infamous flash of wrong theme on page load. I define color tokens as HSL values which makes it easy to create consistent color palettes and adjust lightness for different states (hover, active, etc.).
I use next-themes + CSS variables for its simplicity and Next.js integration. Alternatively, you could implement theme switching with React Context, Zustand, or CSS-in-JS solutions like styled-components or Emotion. The CSS variables pattern works with any approach — the key is defining semantic color tokens that adapt to each theme.
How it works
lib/
└── providers/
└── theme-provider.tsx # Theme provider wrapper
components/
└── common/
└── ThemeToggle.tsx # Theme toggle button
styles/
└── globals.css # CSS variables for themes
tailwind.config.ts # Tailwind theme configuration
app/
└── layout.tsx # Root layout with providerCSS Variables
Use HSL color format for easy theme customization and consistent colors.
Class-based
Using Tailwind's class strategy with next-themes for seamless switching.
System Preference
Auto detect and apply user's OS theme preference.
No Flash
Prevents flash of unstyled content with suppressHydrationWarning.
Key Features
- •CSS variables for flexible theming
- •System preference detection
- •Persistent theme selection
- •No flash on page load
- •Easy to add new themes
Live Example
Theme Switcher Demo
Preview
Card Title
This is how your content looks in light mode.