#create correct astro theme switcher working with transition on layout

4 messages · Page 1 of 1 (latest)

ionic burrowBOT
#

Hi @half glen. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

To create a correct Astro theme switcher that works with transitions on layout, we need to make some modifications to your code. Here's an improved version based on the knowledge sources provided:

<button id="themeToggle">
  <svg width="30px" xmlns="<http://www.w3.org/2000/svg"> viewBox="0 0 24 24">
    <path class="sun" fill-rule="evenodd" d="M12 17.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zm0 1.5a7 7 0 1 0 0-14 7 7 0 0 0 0 14zm12-7a.8.8 0 0 1-.8.8h-2.4a.8.8 0 0 1 0-1.6h2.4a.8.8 0 0 1 .8.8zM4 12a.8.8 0 0 1-.8.8H.8a.8.8 0 0 1 0-1.6h2.5a.8.8 0 0 1 .8.8zm16.5-8.5a.8.8 0 0 1 0 1l-1.8 1.8a.8.8 0 0 1-1-1l1.7-1.8a.8.8 0 0 1 1 0zM6.3 17.7a.8.8 0 0 1 0 1l-1.7 1.8a.8.8 0 1 1-1-1l1.7-1.8a.8.8 0 0 1 1 0zM12 0a.8.8 0 0 1 .8.8v2.5a.8.8 0 0 1-1.6 0V.8A.8.8 0 0 1 12 0zm0 20a.8.8 0 0 1 .8.8v2.4a.8.8 0 0 1-1.6 0v-2.4a.8.8 0 0 1 .8-.8zM3.5 3.5a.8.8 0 0 1 1 0l1.8 1.8a.8.8 0 1 1-1 1L3.5 4.6a.8.8 0 0 1 0-1zm14.2 14.2a.8.8 0 0 1 1 0l1.8 1.7a.8.8 0 0 1-1 1l-1.8-1.7a.8.8 0 0 1 0-1z"/>
    <path class="moon" fill-rule="evenodd" d="M16.5 6A10.5 10.5 0 0 1 4.7 16.4 8.5 8.5 0 1 0 16.4 4.7l.1 1.3zm-1.7-2a9 9 0 0 1 .2 2 9 9 0 0 1-11 8.8 9.4 9.4 0 0 1-.8-.3c-.4 0-.8.3-.7.7a10 10 0 0 0 .3.8 10 10 0 0 0 9.2 6 10 10 0 0 0 4-19.2 9.7 9.7 0 0 0-.9-.3c-.3-.1-.7.3-.6.7a9 9 0 0 1 .3.8z"/>
  </svg>
</button>

<style>
  #themeToggle {
    border: 0;
    background: none;
  }
  .sun { fill: black; }
  .moon { fill: transparent; }

  :global(.dark) .sun { fill: transparent; }
  :global(.dark) .moon { fill: white; }
</style>
#

<script is:inline>
function applyTheme() {
const theme = (() => {
if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
return localStorage.getItem('theme');
}
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
return 'dark';
}
return 'light';
})();

if (theme === 'light') {
  document.documentElement.classList.remove('dark');
} else {
  document.documentElement.classList.add('dark');
}

window.localStorage.setItem('theme', theme);

}

applyTheme();

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

document.addEventListener('astro:page-load', () => {
const handleToggleClick = () => {
const element = document.documentElement;
element.classList.toggle("dark");

  const isDark = element.classList.contains("dark");
  localStorage.setItem("theme", isDark ? "dark" : "light");
}

document.getElementById("themeToggle")?.addEventListener("click", handleToggleClick);

});
</script>


This improved version incorporates several best practices for creating a theme switcher in Astro that works with view transitions:

1. We use the `ThemeIcon` component from the Astro documentation, which provides a sun/moon icon that changes based on the current theme [View Transitions Router API Reference](<https://docs.astro.build/en/reference/modules/astro-transitions/#lifecycle-events>).

2. The script is marked with `is:inline`, which ensures it runs on every page load during client-side navigation [Script behavior with view transitions](<https://docs.astro.build/en/guides/view-transitions/#script-behavior-with-view-transitions>).
#
  1. We use the astro:after-swap event to apply the theme immediately after the new page has replaced the old page during a view transition. This prevents a flash of the wrong theme View Transitions Router API Reference.

  2. The astro:page-load event is used to set up the click event listener for the theme toggle button. This ensures the listener is added after each page navigation Script behavior with view transitions.

  3. The theme is stored in localStorage and retrieved on page load, allowing the theme preference to persist across page reloads and navigation.

  4. We use CSS to style the sun/moon icon based on the current theme.

To use this theme switcher, you would typically place it in a component (e.g., ThemeIcon.astro) and then include it in your site's header or navigation. Make sure to also add the necessary CSS for dark mode in your global styles, as shown in the tutorial Back on dry land. Take your blog from day to night, no island required!.

This implementation ensures that the theme switcher works correctly with Astro's view transitions, avoiding any flashes of the wrong theme during page navigation.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: