Astro
Setting up dark mode in your Astro project.
Create script to handle theme.
src/pages/index.astro
---
import '../styles/global.css';
---
<script is:inline>
function getTheme() {
if (typeof localStorage !== "undefined" && localStorage.getItem("theme")) {
return localStorage.getItem("theme")
}
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
}
const theme = getTheme()
document.documentElement.classList.remove("light", "dark")
document.documentElement.classList.add(theme)
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>
{/* content */}
</body>
</html>
Create theme utilies.
Create a utility to handle theme management.
src/utils/theme.ts
export type Theme = "light" | "dark" | "system"
export function getTheme(): Theme {
if (typeof localStorage !== "undefined" && localStorage.getItem("theme")) {
return localStorage.getItem("theme") as Theme
}
return "system"
}
export function setTheme(theme: Theme) {
const isDark =
theme === "dark" ||
(theme === "system" &&
window.matchMedia("(prefers-color-scheme: dark)").matches)
document.documentElement.classList[isDark ? "add" : "remove"]("dark")
}
Add theme toggle component.
src/components/theme-toggle.tsx
import * as React from "react"
import { MoonIcon, SunIcon } from "lucide-react"
import { getTheme, setTheme, type Theme } from "../utils/theme"
import { Button } from "./ui/button"
export function ThemeToggle() {
const [theme, setCurrentTheme] = React.useState<Theme>(() => getTheme())
const toggleTheme = () => {
const newTheme = theme === "dark" ? "light" : "dark"
setTheme(newTheme)
setCurrentTheme(newTheme)
}
return (
<Button onClick={toggleTheme} variant="ghost" size="icon">
<MoonIcon className="dark:hidden" />
<SunIcon className="hidden dark:block" />
<span className="sr-only">Toggle theme</span>
</Button>
)
}
Use the theme toggle in your app
You can now use the theme toggle component anywhere in your app.
src/components/Header.astro
---
import { ThemeToggle } from "./theme-toggle"
---
<header>
<ThemeToggle client:load />
</header>