| zedkaido.com > writing | RSS

Seamless/Flicker-Free Theme Switching in Svelte-kit

Following are some steps you can follow to implement/fix theme screen flickering on page reload/load. These methods can be adapted to any framework.

Step 1: Create a store for managing theme state:

src/lib/stores/theme.js
import { writable } from 'svelte/store';

const isBrowser = typeof window !== 'undefined';
const storedTheme = isBrowser ? localStorage.theme : null;
const theme = writable(storedTheme || 'system');

if (isBrowser) {
	theme.subscribe(v => {
		localStorage.theme = v;
	});
}

export { theme };

Step 2: In +layout.svelte subscribe to the theme store created in the previous step and update the document.body class list to the current value of the store.

src/routes/+layout.svelte
<script>
import { theme } from '$lib/stores/theme';
	import { onMount } from 'svelte';

	onMount(() => {
		theme.subscribe(v => {
			const bodyClassList = document.body.classList;
			bodyClassList.remove('light', 'system', 'dark');
			bodyClassList.add(v);
		});
	});
</script>

Step 3: Add your preffered method for theme switching:

src/routes/+layout.svelte
<div class="header">
	<select bind:value={$theme} class="theme-selector">
		<option value="system">System</option>
		<option value="light">Light</option>
		<option value="dark">Dark</option>
	</select>
</div>

Step 4: Create a stylesheet.css file and define CSS variables for light and dark themes using the prefers-color-scheme media query.

src/lib/styles/stylesheet.css
/* Define light theme styles */
@media screen and (prefers-color-scheme: light) {
	:root {
		/* Light theme CSS variables */
	}
	body.dark {
		/* Override specific styles for the dark theme */
	}
}

/* Define dark theme styles */
@media screen and (prefers-color-scheme: dark) {
	:root {
		/* Dark theme CSS variables */
	}
	body.light {
		/* Override specific styles for the light theme */
	}
}

Step 5: In app.html, set the initial theme class on document.body based on the stored theme or user's color scheme preference.

app.html
<body data-sveltekit-preload-data="hover">
	<script>
		const storedTheme = localStorage.getItem('theme');
		const systemPreferredTheme = window.matchMedia(
			'(prefers-color-scheme: dark)'
		).matches ? 'dark' : 'light';
		document.body.classList.remove('light', 'dark');
		document.body.classList.add(
			storedTheme ?? systemPreferredTheme
		);
	</script>
</body>

2023-08-01
by Zed Kaido