Themes
Two stylings
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.
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. They are redefined from the configuration:
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
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:
@media (prefers-color-scheme: dark) {
:root:not(.light) {
--dp-bg: #060814;
}
}
:root.dark {
--dp-bg: #060814;
}
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.
<div className="bg-white dark:bg-slate-900">…</div>
Layer order
Under the tailwind theme, the stylesheet declares its layers in this order:
@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:
<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.
DocPensieve