Capítulo 81 de 108
Astro usa um <script is:inline> que roda antes da hidratação de qualquer componente React, aplicando a classe dark no <html> a partir de localStorage/prefers-color-scheme, e observa mudanças de classe para persistir o toggle feito por um ilha React.
<html> (feitas pelo ModeToggle React) e persiste em localStorage.<ModeToggle client:load /> para hidratar o componente React na ilha.ModeToggle mantém seu próprio state React que só sincroniza indiretamente via manipulação direta do classList.<script is:inline>
const getThemePreference = () => {
if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
return localStorage.getItem('theme');
}
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
};
const isDark = getThemePreference() === 'dark';
document.documentElement.classList[isDark ? 'add' : 'remove']('dark');
if (typeof localStorage !== 'undefined') {
const observer = new MutationObserver(() => {
const isDark = document.documentElement.classList.contains('dark');
localStorage.setItem('theme', isDark ? 'dark' : 'light');
});
observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });
}
</script>
React.useEffect(() => {
const isDark = theme === "dark" || (theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches)
document.documentElement.classList[isDark ? "add" : "remove"]("dark")
}, [theme])
<ModeToggle client:load />
MutationObserver do script inline cuida da persistência.client:load no <ModeToggle />: sem a diretiva, o componente React não hidrata e o toggle não funciona.MutationObserver no script inline observando a classe do <html>.