Dark mode in Astro
Create an inline theme script
Create am inline theme script in your index.astro
file
---
import '../styles/globals.css'
---
<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>
<html lang="en">
<body>
<h1>Astro</h1>
</body>
</html>
</script>
Expand
Create a toggle button
Create a toggle button to switch between light and dark themes.
import * as React from "react";
import { MoonIcon, SunIcon } from "@astraicons/react/linear";
import { Button } from "@/app/common/astra-ui/button";
const ThemeButton = () => {
const [theme, setTheme] = React.useState<"light" | "dark" | "system">(
"light"
);
React.useEffect(() => {
const isDarkMode = document.documentElement.classList.contains("dark");
setTheme(isDarkMode ? "dark" : "light");
}, []);
React.useEffect(() => {
const isDark =
theme === "dark" ||
(theme === "system" &&
window.matchMedia("(prefers-color-scheme: dark)").matches);
document.documentElement.classList[isDark ? "add" : "remove"]("dark");
}, [theme]);
return (
<Button
className="flex-shrink-0 p-2.5 ring-0 focus:ring-0 focus:border-none text-grayscale-textIcon-title"
variant="ghost"
size="md"
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
>
<SunIcon className="size-6 transition-all scale-100 rotate-0 dark:-rotate-90 dark:scale-0" />
<MoonIcon className="absolute size-6 transition-all scale-0 rotate-90 dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
);
};
export default ThemeButton;
Expand
Display the mode toggle
Display the ThemeButton
in your application.
---
import '../styles/globals.css'
import ThemeButton from '@/components/theme-button';
---
<!-- Inline script -->
<html lang="en">
<body>
<h1>Astro</h1>
<ThemeButton client:load />
</body>
</html>
Now you can use this toggle in your application to toggle between light and dark themes.