Dark mode
Dark mode is a CSS decision (the dark: variant and what selects it); ShadowJS contributes the state.
Dark mode is a CSS decision (the dark: variant and what selects it); ShadowJS contributes the state. The usual
class-based setup toggles dark on <html>. This component keeps the theme in a signal and applies it in an effect;
the effect never runs on the server, so server markup is unaffected.
src/theme-toggle.tsxtsx
import { onCleanup, useEffect, useStore } from "@shadow-js/core";
export type Theme = "light" | "dark";
export function ThemeToggle(props: { initial?: Theme }) {
const [theme, setTheme] = useStore<Theme>(props.initial ?? "light");
useEffect(() => {
const root = document.documentElement;
root.classList.toggle("dark", theme() === "dark");
onCleanup(() => root.classList.remove("dark"));
});
return (
<button
type="button"
class="rounded-md border px-3 py-1 dark:border-slate-700 dark:text-white"
aria-pressed={theme() === "dark"}
onClick={() => setTheme((current) => (current === "dark" ? "light" : "dark"))}
>
Switch to {theme() === "dark" ? "light" : "dark"}
</button>
);
}