Skip to main content
BLOG.siposdani87

Color scheme change on Astro project

How to adapt to the color scheme change of Astro app

By Dániel Sipos
· · 2 min read

Astro is a framework for building fast and modern websites with components. The code snippet shows how to create a toggle button that switches between light and dark themes for an Astro app. This is the simple implementation of the scheme change function, only the astro-icon package is required for the icons, though even that dependency is optional.

---
import { Icon } from 'astro-icon';
---

The layout of theme toggle buttons:

<label class="swap swap-rotate">
	<!-- this hidden checkbox controls the state -->
	<input type="checkbox" id="themeToggle" />

	<!-- sun icon -->
	<Icon class="swap-on fill-current w-10 h-10" pack="mdi" name="white-balance-sunny" />

	<!-- moon icon -->
	<Icon class="swap-off fill-current w-10 h-10" pack="mdi" name="weather-night" />
</label>

The main logic is the following:

const ATTR_KEY = 'data-theme';
const THEME_KEY = 'app.theme';
const LIGHT_THEME = 'light';
const DARK_THEME = 'dark';

const detectTheme = (): string => {
	if (typeof localStorage !== 'undefined' && localStorage.getItem(THEME_KEY)) {
		return localStorage.getItem(THEME_KEY)!;
	}

	if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
		return DARK_THEME;
	}
	return LIGHT_THEME;
};

const saveTheme = (theme: string) => {
	if (theme) {
		window.localStorage.setItem(THEME_KEY, theme);
	} else {
		window.localStorage.removeItem(THEME_KEY);
	}

	document.documentElement.setAttribute(ATTR_KEY, theme);
	if (theme === LIGHT_THEME) {
		document.documentElement.classList.remove('dark');
	} else {
		document.documentElement.classList.add('dark');
	}
};

const changeTheme = () => {
	const currentTheme = document.documentElement.getAttribute(ATTR_KEY);
	const theme = currentTheme === DARK_THEME ? LIGHT_THEME : DARK_THEME;
	saveTheme(theme);
};

const setTheme = () => {
	const detectedTheme = detectTheme();
	saveTheme(detectedTheme);
	if (detectedTheme === LIGHT_THEME) {
		document.getElementById('themeToggle')?.setAttribute('checked', 'checked');
	}

	document.getElementById('themeToggle')?.addEventListener('click', changeTheme);
};

setTheme();

document.addEventListener('astro:after-swap', setTheme);

Conclusion

This implementation provides a lightweight theme switcher using Astro and TypeScript, persisting the user’s preference in local storage and respecting the system color scheme as a default.

Share with your friends

Related posts