Theme Switcher for SvelteKit

April 15, 2024 Updated: June 17, 2025

Theme Switcher for SvelteKit

Table of Contents

Overview

This guide demonstrates how to create a robust theme switching system for SvelteKit applications. We’ll build a global context store that persists user preferences via cookies, ensuring themes load correctly on the server and preventing flash of unstyled content (FOUC). The implementation includes type-safe cookie management, server-side rendering support, and a complete theme switcher component using DaisyUI.

Dependencies

This implementation requires two key packages for cookie management and data validation:

  • js-cookie: Provides a simple API for handling cookies in the browser
  • valibot: Ensures type safety and validates cookie data structure
bash
pnpm add js-cookie valibot

Why cookies over localStorage? Cookies are accessible on both client and server, making them essential for SSR applications. This prevents FOUC by allowing the server to render the correct theme immediately, rather than waiting for client-side JavaScript to load and apply the theme from localStorage.

Theme Definitions

Define your available themes using DaisyUI’s CSS plugin system. This approach allows you to customize existing themes or create entirely new ones with your brand colors and styling preferences.

Each theme definition includes:

  • name: The theme identifier used in your application
  • default: Whether this is the default theme (only one should be true)
  • prefersdark: Indicates if this theme should be used when system prefers dark mode
  • color-scheme: Tells the browser whether this is a light or dark theme
  • Custom CSS variables: Override default DaisyUI colors with your brand palette

These utility functions provide a unified, type-safe API for managing cookies across both client and server environments in SvelteKit. They handle serialization, validation, and provide seamless integration with your app’s state management.

Key Features:

  • Type Safety: Uses Valibot schemas to ensure data integrity
  • Universal API: Works seamlessly on both client and server
  • Error Handling: Gracefully handles malformed or missing cookies
  • Automatic Serialization: Handles JSON serialization for complex objects
  • Security Options: Supports HTTP-only cookies for sensitive data

Schema and Constants Definition

Define your application’s data structure and available themes using TypeScript and Valibot for complete type safety. The following schema showcases the theme selector options, but is extensible for other user preferences as needed.

Global Context Store

The global context store provides centralized state management for your application settings. Built with Svelte 5’s runes system, it automatically persists changes to cookies and provides reactive updates throughout your app.

Key Features:

  • Reactive State: Uses Svelte 5’s $state rune for fine-grained reactivity
  • Automatic Persistence: Changes are automatically saved to cookies via $effect
  • Type Safety: Full TypeScript support with proper type inference
  • Context-Based: Available throughout your component tree without prop drilling

Setting Up the Global Store

Initialize the global context store in your application’s root layout by loading the cookie data server-side and creating the store instance.

Theme Switcher Component

The theme switcher component demonstrates how to use the global store to create a reactive UI that responds to both user selections and system preferences. It includes automatic mode detection and smooth theme transitions.

Component Features:

  • System Detection: Automatically detects and responds to OS dark mode changes
  • Immediate Updates: Applies theme changes to the DOM instantly for smooth UX
  • Grouped Options: Organizes themes by light/dark categories in the dropdown
  • Reactive State: Automatically syncs with the global store and persists to cookies

Preventing FOUC with Server-Side Theme Preloading

To eliminate flash of unstyled content, we need to apply the correct theme classes to the HTML document before any JavaScript runs. This is achieved by modifying the HTML template during server-side rendering.

How It Works:

  1. Server-Side Detection: The hook reads the user’s theme preference from cookies during SSR
  2. HTML Transformation: Replaces the %theme% placeholder with the appropriate CSS classes
  3. Immediate Application: The correct theme is applied before any JavaScript loads
  4. Route-Specific Logic: Can apply different themes based on the current route

This approach ensures that users see the correct theme immediately, without any flash or delay, providing a seamless user experience across all devices and connection speeds.