[]previous and next page

Dark mode

Dark mode is a CSS decision (the dark: variant and what selects it); ShadowJS contributes the state.

For agentsUpdated

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>
  );
}