> ## Documentation Index
> Fetch the complete documentation index at: https://docs.featherframework.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Dark mode

> A cookie-persisted toggle on every page including the admin panel, with no flash of the wrong theme.

Every scaffolded app includes a dark mode toggle that persists across pages via a `dm`
cookie. The toggle is in the header of every page, including the admin panel.

## How it works

<Steps>
  <Step title="The cookie is read before first paint">
    A `dark-mode.js` script loaded in `<head>` reads the `dm` cookie and applies a
    `.dark` class to `<html>` before first render — so there is no flash of the wrong
    theme.
  </Step>

  <Step title="Any element can toggle it">
    Clicking any element carrying `data-toggle-dark-mode` toggles the class and updates
    the cookie.
  </Step>

  <Step title="Styles respond through a custom variant">
    All CSS uses `dark:` variants via Tailwind's custom variant:
    `@custom-variant dark (&:where(.dark, .dark *))`.
  </Step>
</Steps>

## The toggle button

Scaffolded into your templates:

```html theme={null}
<button data-toggle-dark-mode
        class="p-2 rounded-lg text-gray-500 hover:bg-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 transition-colors"
        title="Toggle dark mode">
    <span class="dark:hidden"><span class="material-symbols-outlined">bedtime</span></span>
    <span class="hidden dark:inline"><span class="material-symbols-outlined">sunny</span></span>
</button>
```

The only thing `dark-mode.js` looks for is the `data-toggle-dark-mode` attribute. Which
icon shows is plain `dark:` variants on the two spans. If you would rather keep the
markup clean, move the swap into `app.css` and give the button a class of your own:

```css app.css theme={null}
.dark-mode-toggle .icon-light { @apply dark:hidden; }
.dark-mode-toggle .icon-dark  { @apply hidden dark:inline; }
```

## Writing dark-mode-aware styles

When adding custom styles, include `dark:` variants for every color-related class.
Feather recommends CSS classes with `@apply` rather than inline Tailwind, so dark mode
support looks like this:

```css app.css theme={null}
.my-card {
    @apply bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100
           border border-gray-200 dark:border-gray-700;
}
```

<Tip>
  Utility classes in markup instead of `@apply` in `app.css` are reported by
  [`feather check`](/tooling/check) as the `inline-tailwind` warning. Keeping styles in
  the stylesheet is what makes a one-line dark mode audit possible.
</Tip>
