# Themes

> Style the site, and change the classes without touching the HTML.

## Two stylings

```js
theme: {
  framework: 'tailwind',
  darkMode: 'class',
},
```

`tailwind` compiles on demand only the classes actually used in the produced
pages. `custom` does without it entirely: a stylesheet written in the package
styles the site, with no styling dependency.

The templates are the same in both cases. Switching values requires touching
no page.

## The principle: slots, not classes

The templates **hard-code no class**. They ask the theme for the class of each
slot — the header, the menu, a navigation link — and the theme answers.

The twenty-four slots are listed in the [reference](/versions/v0.2/reference/theme/).

That is what lets a utility styling and a classic styling share the same HTML:
one answers `dp-nav-link`, the other a handful of utilities. The template
itself does not change.

Components follow the same rule. When the theme does not answer, they fall
back on a `dp-*` class that their stylesheet styles from the `--dp-*` tokens:
they therefore follow the active palette without knowing anything about it.

## Changing the colours

The fifteen tokens are listed in the [reference](/versions/v0.2/reference/theme/). They are
redefined from the configuration:

```js
theme: {
  framework: 'tailwind',
  tokens: {
    '--dp-accent': 'oklch(55% 0.2 250)',
    '--dp-radius': '0.75rem',
  },
},
```

| Token                                  | What it sets                                                   |
| -------------------------------------- | -------------------------------------------------------------- |
| `--dp-bg`, `--dp-bg-soft`              | Backgrounds                                                    |
| `--dp-text`, `--dp-text-soft`          | Text                                                           |
| `--dp-border`, `--dp-rule`             | Borders and rules                                              |
| `--dp-accent`, `--dp-accent-soft`      | Accent colour                                                  |
| `--dp-radius`                          | Corner rounding                                                |
| `--dp-font`, `--dp-font-mono`          | Font families                                                  |
| `--dp-content-width`                   | Reading width. `none` by default: the content fills its column |
| `--dp-sidebar-width`, `--dp-toc-width` | Side columns                                                   |

A redefined token propagates everywhere: components included, without any of
them having to know.

## Adding CSS

```js
theme: {
  framework: 'tailwind',
  css: '.dp-article h2 { letter-spacing: -0.01em; }',
},
```

The content of `css` is appended to the produced stylesheet.

## Colour scheme

`theme.darkMode` decides which palette the reader gets. `'class'`, the default,
follows the reader's system; `'dark'` or `'light'` keeps one whatever the
system — the build sets it as a class on `<html>`.

The header also carries a button that switches between light and dark, and
remembers the reader's choice from page to page — a few hundred bytes of inline
script, the only one content pages carry. `theme.toggle: false` removes it.
Without JavaScript, the button does not show.

The dark palette is a set of tokens, the same under both themes. To change it,
redefine them in the `theme/` folder, for both ways of being dark — the
system's scheme, and the class that `darkMode: 'dark'` sets:

```css
@media (prefers-color-scheme: dark) {
  :root:not(.light) {
    --dp-bg: #060814;
  }
}

:root.dark {
  --dp-bg: #060814;
}
```

<ForTheme framework="tailwind">

The `dark:` utilities of your pages follow the same rule: they apply under the
system's dark scheme, and always once `darkMode: 'dark'` is set.

```mdx
<div className="bg-white dark:bg-slate-900">…</div>
```

</ForTheme>
<ForTheme framework="custom">

Your own classes follow it through the same two selectors:

```css
:root.dark .note {
  border-color: var(--dp-accent);
}
```

</ForTheme>

## Layer order

Under the `tailwind` theme, the stylesheet declares its layers in this order:

```css
@layer theme, base, components, utilities;
```

Component rules live in `components`, **below** the utilities. A `className`
set at use therefore always wins, whatever the place of the rule in the file:

```mdx
<Card className="border-0 shadow-none">…</Card>
```

Without this layer, a component rule written after a utility would beat it at
equal specificity, and the author's `className` would be ignored without a
word.

The `custom` theme has no utilities: a `className` there names classes of your
own. Write them in the `theme/` folder, at the root of the project: every `.css`
file in it is appended to the stylesheet, outside any layer, so they come
before the component rules. Under this theme, `init` starts the folder with
`theme/custom.css`.

## The stylesheet is compiled last

A utility theme only emits the rules of the classes actually used: it
therefore needs the rendered pages before it can compile. The build first
writes every page, collecting the classes along the way, then compiles the
stylesheet.

That is also why the slot classes are available **without** waiting for that
compilation: the templates need them to be rendered. The two things are kept
apart for this reason alone.
