Color scheme change on Astro project
How to adapt to the color scheme change of Astro app
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:
detectTheme: This function returns the current theme based on the local storage value or the user’s preferred color scheme.
saveTheme: This function saves the theme preference to the local storage and sets the data attribute and the class of the document element accordingly.
changeTheme: This function toggles the theme between light and dark and calls the saveTheme function.
setTheme: This function sets the initial theme based on the detectTheme function and adds a click event listener to the checkbox input to call the changeTheme function. It also adds an astro:after-swap event listener to the document to call the setTheme function again after the Astro component is swapped.
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.