Presets

Nine built-in palettes for light and dark, a picker for trying them live, and how to extend one with your own colours.

A preset is a complete set of the fifteen colour tokens for both light and dark. Four are gray palettes that keep the monochrome look and differ only in tint and contrast; five add a tinted surface scale and a real accent colour for links, active tabs and focus rings. Every preset supports light and dark, so the theme toggle keeps working whichever one you choose.

Try them#

The picker below applies a preset to this page and remembers it in local storage. Switch the theme with the toggle in the header to see both schemes.

Click mono to return to the default.

Choosing a preset#

Set theme.preset. It is applied before any colors overrides, so you can start from the closest palette and change only a few values.

docs.config.ts
theme: {
  preset: "ocean",
}
PresetCharacterAccent
monoNeutral grays with no tint. The default, and the set of values baked into the stylesheet.Same as the foreground
slateCool, slightly blue-tinted grays.Same as the foreground
warmWarm paper and ink grays.Same as the foreground
contrastPure white and black with firmer borders.Same as the foreground
oceanBlue-tinted surfaces with a blue accent.#2563eb / #60a5fa
duskViolet-tinted surfaces with a violet accent.#7c3aed / #a78bfa
forestGreen-tinted surfaces with a green accent.#15803d / #4ade80
emberWarm sand surfaces with an orange accent.#ea580c / #fb923c
roseRose-tinted surfaces with a crimson accent.#e11d48 / #fb7185

Because mono is already the stylesheet default, choosing it emits no colour declarations. Every other preset expands to all fifteen tokens for :root and for .dark.

The accent token#

--pd-accent colours prose links, the active header tab underline, active tab and code tab underlines, and --pd-accent-foreground is the text colour for anything placed on an accent background. In the gray presets the accent equals the foreground, which is why they stay strictly monochrome. The tinted presets also use the accent as the focus ring.

Letting readers pick#

ThemePresetPicker from pzzadocs/ui is the component used above. Drop it into any page or into a layout slot to let visitors choose their own palette; the selection is written as a <style> element after the config styles and stored under the storageKey.

tsx
import { ThemePresetPicker } from "pzzadocs/ui";

<ThemePresetPicker presets={["mono", "ocean", "dusk"]} defaultPreset="mono" storageKey="my-docs-preset" />
NameTypeDefaultDescription
presetsThemePreset[]all presetsPresets to offer, in display order.
defaultPresetThemePreset"mono"The preset the site is configured with. Selecting it removes the override.
storageKeystring | null"pd-preset"localStorage key for the choice. null forgets it on reload.
onChange(preset: ThemePreset) => void-Called after a preset is applied.

The picker is applied after hydration, so a stored choice appears a moment after first paint. For a fixed site-wide palette use theme.preset in the config instead, which is rendered on the server.

mono#

Neutral grays with no tint.

KeyTokenLightDark
background--pd-background#fafafa#0c0c0c
surface--pd-surface#ffffff#121212
surface2--pd-surface-2#f2f2f2#1a1a1a
surface3--pd-surface-3#e9e9e9#232323
foreground--pd-foreground#111111#ececec
foreground2--pd-foreground-2#3d3d3d#c4c4c4
mutedForeground--pd-muted-foreground#707070#8a8a8a
faintForeground--pd-faint-foreground#a3a3a3#5c5c5c
border--pd-border#e4e4e4#242424
borderStrong--pd-border-strong#cfcfcf#343434
sidebar--pd-sidebar#fafafa#0c0c0c
ring--pd-ring#111111#ececec
overlay--pd-overlayrgba(0, 0, 0, 0.4)rgba(0, 0, 0, 0.6)
accent--pd-accent#111111#ececec
accentForeground--pd-accent-foreground#fafafa#0c0c0c

slate#

Cool, slightly blue-tinted grays.

KeyTokenLightDark
background--pd-background#f8f9fb#0b0e12
surface--pd-surface#ffffff#11151b
surface2--pd-surface-2#eff1f5#181d25
surface3--pd-surface-3#e4e7ed#20262f
foreground--pd-foreground#0f1419#e6eaf0
foreground2--pd-foreground-2#3b434f#c0c7d1
mutedForeground--pd-muted-foreground#6b7380#8690a0
faintForeground--pd-faint-foreground#9aa3b0#596273
border--pd-border#e2e6ec#222933
borderStrong--pd-border-strong#c9cfd8#323b47
sidebar--pd-sidebar#f8f9fb#0b0e12
ring--pd-ring#0f1419#e6eaf0
overlay--pd-overlayrgba(10, 14, 20, 0.45)rgba(0, 0, 0, 0.6)
accent--pd-accent#0f1419#e6eaf0
accentForeground--pd-accent-foreground#f8f9fb#0b0e12

warm#

Warm paper and ink grays.

KeyTokenLightDark
background--pd-background#fbfaf8#0f0e0d
surface--pd-surface#ffffff#161412
surface2--pd-surface-2#f3f1ed#1f1c19
surface3--pd-surface-3#e9e6e0#282420
foreground--pd-foreground#1a1816#ebe6df
foreground2--pd-foreground-2#44403b#c6bfb6
mutedForeground--pd-muted-foreground#746e67#8f877e
faintForeground--pd-faint-foreground#a69f97#5f5850
border--pd-border#e6e2db#27231f
borderStrong--pd-border-strong#d2ccc3#383229
sidebar--pd-sidebar#fbfaf8#0f0e0d
ring--pd-ring#1a1816#ebe6df
overlay--pd-overlayrgba(20, 16, 12, 0.45)rgba(0, 0, 0, 0.6)
accent--pd-accent#1a1816#ebe6df
accentForeground--pd-accent-foreground#fbfaf8#0f0e0d

contrast#

Pure white and black with firmer borders.

KeyTokenLightDark
background--pd-background#ffffff#000000
surface--pd-surface#ffffff#000000
surface2--pd-surface-2#f0f0f0#161616
surface3--pd-surface-3#e0e0e0#262626
foreground--pd-foreground#000000#ffffff
foreground2--pd-foreground-2#1f1f1f#e8e8e8
mutedForeground--pd-muted-foreground#4a4a4a#b4b4b4
faintForeground--pd-faint-foreground#767676#8c8c8c
border--pd-border#c8c8c8#3a3a3a
borderStrong--pd-border-strong#8a8a8a#6a6a6a
sidebar--pd-sidebar#ffffff#000000
ring--pd-ring#000000#ffffff
overlay--pd-overlayrgba(0, 0, 0, 0.55)rgba(0, 0, 0, 0.7)
accent--pd-accent#000000#ffffff
accentForeground--pd-accent-foreground#ffffff#000000

ocean#

Blue-tinted surfaces with a blue accent.

KeyTokenLightDark
background--pd-background#f7f9fc#0a0f17
surface--pd-surface#ffffff#0f1621
surface2--pd-surface-2#edf2f8#161f2c
surface3--pd-surface-3#e1e8f1#1e2937
foreground--pd-foreground#0e1620#e4ebf5
foreground2--pd-foreground-2#334155#b9c5d6
mutedForeground--pd-muted-foreground#64748b#7f8ea3
faintForeground--pd-faint-foreground#94a3b8#52607a
border--pd-border#e0e7ef#1f2a3a
borderStrong--pd-border-strong#c7d2df#2d3b4f
sidebar--pd-sidebar#f7f9fc#0a0f17
ring--pd-ring#2563eb#60a5fa
overlay--pd-overlayrgba(8, 16, 30, 0.45)rgba(0, 0, 0, 0.6)
accent--pd-accent#2563eb#60a5fa
accentForeground--pd-accent-foreground#ffffff#0a0f17

dusk#

Violet-tinted surfaces with a violet accent.

KeyTokenLightDark
background--pd-background#faf9fc#0e0b14
surface--pd-surface#ffffff#14101c
surface2--pd-surface-2#f2f0f7#1c1726
surface3--pd-surface-3#e8e4f0#261f32
foreground--pd-foreground#17121f#ece8f3
foreground2--pd-foreground-2#3f3650#c3bbd1
mutedForeground--pd-muted-foreground#6f6682#8d849e
faintForeground--pd-faint-foreground#a097b2#5c536d
border--pd-border#e6e2ee#241e30
borderStrong--pd-border-strong#cfc8db#352d44
sidebar--pd-sidebar#faf9fc#0e0b14
ring--pd-ring#7c3aed#a78bfa
overlay--pd-overlayrgba(14, 10, 22, 0.45)rgba(0, 0, 0, 0.6)
accent--pd-accent#7c3aed#a78bfa
accentForeground--pd-accent-foreground#ffffff#0e0b14

forest#

Green-tinted surfaces with a green accent.

KeyTokenLightDark
background--pd-background#f8faf8#0a100c
surface--pd-surface#ffffff#0f1711
surface2--pd-surface-2#eef3ee#162018
surface3--pd-surface-3#e2eae3#1e2a21
foreground--pd-foreground#101a13#e5efe8
foreground2--pd-foreground-2#334238#b8c8bd
mutedForeground--pd-muted-foreground#65736a#7e9285
faintForeground--pd-faint-foreground#96a39a#51625a
border--pd-border#e0e8e2#1f2b23
borderStrong--pd-border-strong#c6d3c9#2e3d33
sidebar--pd-sidebar#f8faf8#0a100c
ring--pd-ring#15803d#4ade80
overlay--pd-overlayrgba(8, 18, 12, 0.45)rgba(0, 0, 0, 0.6)
accent--pd-accent#15803d#4ade80
accentForeground--pd-accent-foreground#ffffff#0a100c

ember#

Warm sand surfaces with an orange accent.

KeyTokenLightDark
background--pd-background#fcfaf7#110d0a
surface--pd-surface#ffffff#17120e
surface2--pd-surface-2#f6f1ea#201913
surface3--pd-surface-3#ede5da#2a2119
foreground--pd-foreground#1c1510#f0e9e2
foreground2--pd-foreground-2#4a3d33#cbc0b5
mutedForeground--pd-muted-foreground#7a6b5e#978a7d
faintForeground--pd-faint-foreground#ab9d90#635749
border--pd-border#ece4da#2a221b
borderStrong--pd-border-strong#d7cabb#3c3129
sidebar--pd-sidebar#fcfaf7#110d0a
ring--pd-ring#ea580c#fb923c
overlay--pd-overlayrgba(22, 14, 8, 0.45)rgba(0, 0, 0, 0.6)
accent--pd-accent#ea580c#fb923c
accentForeground--pd-accent-foreground#ffffff#110d0a

rose#

Rose-tinted surfaces with a crimson accent.

KeyTokenLightDark
background--pd-background#fcf9fa#120b0e
surface--pd-surface#ffffff#181013
surface2--pd-surface-2#f6eff2#211719
surface3--pd-surface-3#ede3e7#2b1f23
foreground--pd-foreground#1c1116#f1e8eb
foreground2--pd-foreground-2#4a3640#cdbec4
mutedForeground--pd-muted-foreground#7a6670#988790
faintForeground--pd-faint-foreground#ab979f#645258
border--pd-border#ecdfe4#2c2025
borderStrong--pd-border-strong#d8c5cd#3f2f36
sidebar--pd-sidebar#fcf9fa#120b0e
ring--pd-ring#e11d48#fb7185
overlay--pd-overlayrgba(22, 8, 14, 0.45)rgba(0, 0, 0, 0.6)
accent--pd-accent#e11d48#fb7185
accentForeground--pd-accent-foreground#ffffff#120b0e

Extending a preset#

colors is applied after the preset, per colour scheme, and only the keys you set are emitted. Start from the preset that is closest to what you want and override the rest:

docs.config.ts
theme: {
  preset: "ocean",
  colors: {
    light: {
      accent: "#0f766e",
      ring: "#0f766e",
    },
    dark: {
      accent: "#2dd4bf",
      ring: "#2dd4bf",
      background: "#000000",
      sidebar: "#000000",
    },
  },
}

Any CSS colour string is accepted, including rgb(), hsl(), oklch() and var() references to your own properties. The values land in the same <style> element as the preset, so the override is present on first paint. See the ThemeColors reference for what each key is used for.