Color scheme change on Astro project
How to adapt to the color scheme change of Astro app By: Dániel Sipos onAstro 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, but this is also not mandatory…
---
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);
Final words
The code snippet is a demonstration of how to create a simple and elegant theme switcher for an app using Astro markup and TypeScript. It shows how to use the astro-icon library to render icons, and how to use local storage, data attributes, and event listeners to handle the theme logic.