Skip to main content

Dark Theme Implementation

Architecture

Three-Layer System:

  1. Server-side detection (+layout.server.ts) - reads theme cookie, defaults to light
  2. Client-side reactivity (Svelte 5 store with $state) - handles theme changes
  3. CSS implementation (light-dark() + color-scheme) - automatic theme switching

Key Files

  • lib/stores/theme.svelte.ts - Svelte 5 store with toggle method
  • lib/components/ui/ThemeToggle.svelte - animated toggle with icons + cookie persistence
  • routes/+layout.server.ts - server-side theme detection from cookies
  • routes/+layout.svelte - applies data-theme attribute + color-scheme CSS
  • theme.scss - CSS custom properties using light-dark() function

Implementation Details

Store Pattern:

class ThemeStore {
theme: Theme = $state(initTheme)
toggle() { this.theme = this.theme === 'dark' ? 'light' : 'dark' }
}

CSS Strategy:
- Uses light-dark() function for automatic theme switching
- Sets color-scheme: light/dark on <html> for native browser elements
- All colors defined as CSS custom properties with light/dark values

CSS Color Scheme:
/* Change the global color schema */
:global(html) {
color-scheme: light;
}

:global(html:has(.container[data-theme='dark'])) {
color-scheme: dark;
}

Persistence:
- Theme stored in cookie with 1-year expiration
- Server reads cookie on page load for SSR
- Client updates cookie via $effect when theme changes

Toggle Component:
- Checkbox input with animated sun/moon icons
- Grid-based overlay system for smooth transitions
- Reactive to store changes with visual feedback