# Dark Mode

Adding dark mode to your Astro project.

## Create an inline theme script

```astro title="src/layouts/index.astro"
---
---

<div class="relative text-sm">
  <div class="absolute z-10 left-3 top-2.5 pointer-events-none">
    <SunIcon class="size-4 dark:hidden" />
    <MoonIcon class="size-4 hidden dark:block" />
  </div>
  <Select id="theme-select" class="w-28">
    <SelectTrigger class="pl-9">
      <SelectValue placeholder="Theme" />
    </SelectTrigger>
    <SelectContent>
      <SelectItem value="light">Light</SelectItem>
      <SelectItem value="dark">Dark</SelectItem>
      <SelectItem value="auto">Auto</SelectItem>
    </SelectContent>
  </Select>
</div>

<script is:inline>
  // @ts-nocheck
  const storageKey = "starlight-theme";
  const themeMetaMedias = [
    "(prefers-color-scheme: light)",
    "(prefers-color-scheme: dark)",
  ];
  const themeColors = {
    light: "#ffffff",
    dark: "#0f171f",
  };

  const parseTheme = (theme) =>
    theme === "auto" || theme === "dark" || theme === "light" ? theme : "auto";

  const loadTheme = () => {
    try {
      if (typeof localStorage !== "undefined") {
        return parseTheme(localStorage.getItem(storageKey));
      }
    } catch {}
    return "auto";
  };

  function storeTheme(theme) {
    try {
      if (typeof localStorage !== "undefined") {
        localStorage.setItem(
          storageKey,
          theme === "light" || theme === "dark" ? theme : "",
        );
      }
    } catch {}
  }

  function ensureThemeMeta(head, media) {
    const baseSelector = `meta[name="theme-color"][media="${media}"]`;

    let meta = head.querySelector(`${baseSelector}[data-theme-managed]`);
    if (meta instanceof HTMLMetaElement) return meta;

    meta = head.querySelector(baseSelector);
    if (meta instanceof HTMLMetaElement) {
      meta.setAttribute("data-theme-managed", "");
      return meta;
    }

    meta = document.createElement("meta");
    meta.setAttribute("name", "theme-color");
    meta.setAttribute("media", media);
    meta.setAttribute("data-theme-managed", "");
    head.appendChild(meta);
    return meta;
  }

  function syncThemeColor(theme) {
    const color = themeColors[theme];
    const head = document.head;
    if (!color || !head) return;

    themeMetaMedias.forEach((media) => {
      const meta = ensureThemeMeta(head, media);
      meta.setAttribute("content", color);
    });
  }

  const getPreferredColorScheme = () =>
    matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark";

  function applyTheme(theme) {
    const effective = theme === "auto" ? getPreferredColorScheme() : theme;
    document.documentElement.dataset.theme = effective;
    document.documentElement.classList.remove("light", "dark");
    document.documentElement.classList.add(effective);
    syncThemeColor(effective);
    storeTheme(theme);
    const select = document.getElementById("theme-select");
    if (select instanceof HTMLSelectElement) select.value = theme;
  }

  // Initialize
  applyTheme(loadTheme());

  // UI: select changes
  const select = document.getElementById("theme-select");
  if (select) {
    select.addEventListener("select:change", (e) => {
      const { value } = e.detail;
      applyTheme(parseTheme(value));
    });
  }

  window.toggleTheme = (theme) => applyTheme(parseTheme(theme));

  // React to system scheme changes while in 'auto'
  matchMedia("(prefers-color-scheme: light)").addEventListener("change", () => {
    if (loadTheme() === "auto") applyTheme("auto");
  });
</script>
```

## Display the mode toggle

<div class="not-content">
  <ThemeSwitcher />
</div>

Place a mode toggle on your site to toggle between light and dark mode.

```astro title="src/pages/index.astro"
---
---

<!-- Inline script -->
<html lang="en">
  <body>
    <h1>Astro</h1>
    <ThemeSwitcher client:load />
  </body>
</html>
```