Mode Watcher
repository·main·Indexed 20 days ago
https://github.com/svecosystem/mode-watcherA utility library for SvelteKit applications to manage light and dark modes. It provides automatic OS preference detection, persistence via localStorage, and theme color management. Key features include the ModeWatcher component for root layout integration, functions like toggleMode, setMode, and resetMode, and readable stores for tracking resolved mode, user preferences, and system settings without causing a flash of unstyled content (FOUC).
What's inside mode-watcher
- Mode Watcher is a utility library for Svelte applications designed to manage light and dark modes with minimal configuration. It is built to be compatible with Server-Side Rendering (SSR), Client-Side Rendering (CSR), and Static Site Generation (SSG) without causing a flash of unstyled content (FOUC).
Understand userPrefersMode and systemPrefersMode stores
mainMode Watcher provides two stores for tracking different preference layers:
userPrefersMode: A writable store representing the user's chosen mode preference. It accepts"light","dark", or"system".systemPrefersMode: A readable store representing the operating system's mode preference. It returns"light","dark", orundefined(on the server). It tracks OS changes unlesstrack={false}is passed to theModeWatchercomponent.
Difference between `mode` and `userPrefersMode`
mainWhen managing themes, it is important to distinguish between the resolved mode and the user's explicit preference:
mode: The actual active theme (always"light"or"dark"). This is what you use to determine how to style components or logic.userPrefersMode: The user's specific selection, which can be"light","dark", or"system".
If you need to know if a user has opted to follow the system settings, use
userPrefersModeinstead ofmode.Key features of Mode Watcher
mainMode Watcher provides several automated theme management features:
- Real-time detection: Tracks
prefers-color-schemechanges automatically. - Persistence: Uses
localStorageto save user preferences and sync themes across different tabs and windows. - System Integration: Updates the
color-schemeCSS property (for scrollbars and form controls) and thetheme-colormeta tag (for the browser interface). - Smooth Transitions: Automatically disables CSS transitions during theme changes to prevent flickering.
- Flexible Defaults: Allows setting a default theme and provides options to toggle between light/dark modes or respect system preferences.
- Real-time detection: Tracks
Use the theme state to track granular visual styles
mainThe
themestate is a readable state that holds the currently active theme as a string. Unlikemode(which is restricted to"light"or"dark"),themeallows you to define and track any custom string (e.g.,"dracula","retro", or"corporate"). This is useful for supporting multiple granular visual styles beyond simple light/dark modes. You can access the current value viatheme.currentand update it usingsetTheme.<script lang="ts"> import { setTheme, theme } from "mode-watcher"; function cycleTheme() { if (theme.current === "dracula") { setTheme("retro"); } else { setTheme("dracula"); } } </script> <button onclick={cycleTheme}>{theme.current}</button>Understand the difference between Mode and Theme
mainIn Mode Watcher, Mode and Theme are distinct layers of customization that work together:
Mode
Represents the user's preference for the interface appearance. It controls the technical implementation of light/dark styles by:
- Applying the
lightordarkclass to the root<html>element. - Setting the
color-scheme(lightordark) for browser rendering.
Possible mode values:
"light""dark""system"(follows the operating system's preference)
Theme
Represents your application's design system (colors, typography, spacing, etc.). A single theme can contain both light and dark variants. Instead of creating separate themes for different modes (e.g.,
dracula-lightanddracula-dark), you should provide one theme (e.g.,dracula) that includes both variants. Mode Watcher will automatically select the correct variant based on the active mode.- Applying the
Install mode-watcher via npm
mainInstall the
mode-watcherpackage using npm to add theme mode management to your Svelte application.npm install mode-watcherUse `createInitialModeExpression` to prevent theme flashing in SvelteKit
mainIn SvelteKit applications, you can use
createInitialModeExpressionto generate a secure, inline JavaScript snippet that sets the initial color mode (light, dark, or system) before the page hydrates. This prevents the 'flash of unstyled content' (FOUC) where the theme jumps from light to dark (or vice versa) during page load.This utility is specifically designed for environments with strict Content Security Policies (CSP) that require a
noncefor inline scripts.import { createInitialModeExpression } from "mode-watcher"; // Returns a string containing the inline script logic const snippet = createInitialModeExpression();Setup the ModeWatcher component
mainTo use mode-watcher, add the
ModeWatchercomponent to your root+layout.sveltefile. This component automatically detects user preferences and applies the"dark"class andcolor-schemestyle attribute to thehtmlelement.Configuration Props
track(boolean): If set tofalse, the component will stop tracking operating system preference changes.defaultMode(string): Sets a default mode (e.g.,"dark") instead of automatic detection.themeColors(object): Configures thetheme-colormeta tag. Accepts an object withdarkandlightkeys.
Example configuration:
<script lang="ts"> import { ModeWatcher } from "mode-watcher"; let { children } = $props(); </script> <ModeWatcher track={true} defaultMode="light" themeColors={{ dark: "black", light: "white" }} /> {@render children()}Install and use the ModeWatcher component
mainTo automatically apply mode and theme preferences in a SvelteKit application, add the
ModeWatchercomponent to your root+layout.sveltefile.ModeWatcherperforms the following actions:- Detects user mode preferences (
light,dark, orsystem). - Applies the appropriate class (defaulting to
dark) to the<html>element. - Sets the
color-schemeattribute on the<html>element. - Optionally applies a theme via the
data-themeattribute.
<script lang="ts"> import { ModeWatcher } from "mode-watcher"; let { children } = $props(); </script> <ModeWatcher /> {@render children()}- Detects user mode preferences (
Install mode-watcher
mainInstall the
mode-watcherpackage using npm to manage light and dark modes in your SvelteKit application.npm install mode-watcherBuild and preview a Svelte project
mainTo prepare your application for production, run the
buildscript. Once the build is complete, you can use thepreviewscript to run a local server that serves the production build for testing.# Create a production version of your app npm run build # Preview the production build npm run preview