BLOG.siposdani87

Color scheme change on Astro project

How to adapt to the color scheme change of Astro app
By: Dániel Sipos on

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, 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:

    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.

Share with your friends

Related posts