Theme

Full reference for ThemeConfig, the colour and code token types, the design tokens, ThemeStyles and resolveThemeCss.

ts
import { resolveThemeCss } from "pzzadocs";
import { ThemeStyles } from "pzzadocs/ui";
import type {
  ThemeConfig,
  ResolvedThemeConfig,
  ThemeColors,
  CodeTokenColors,
  CodeThemePair,
  ThemePreset,
  ThemeDensity,
  ThemeFonts,
  ThemeLayout,
} from "pzzadocs";

ThemeConfig#

The theme section of DocsConfig. defineConfig fills in defaultTheme, hotKey, preset, codeTheme and density and returns a ResolvedThemeConfig; the override sections stay partial.

ts
interface ThemeConfig {
  defaultTheme?: "light" | "dark" | "system";
  hotKey?: boolean;
  preset?: ThemePreset;
  colors?: { light?: Partial<ThemeColors>; dark?: Partial<ThemeColors> };
  code?: { light?: Partial<CodeTokenColors>; dark?: Partial<CodeTokenColors> };
  codeTheme?: "pzza" | CodeThemePair;
  radius?: number | string;
  fonts?: ThemeFonts;
  layout?: ThemeLayout;
  density?: ThemeDensity;
}
NameTypeDefaultDescription
defaultTheme"light" | "dark" | "system""system"Theme before the visitor picks one.
hotKeybooleantruePressing D outside inputs and with the search dialog closed toggles light and dark.
presetThemePreset"mono"Built-in palette applied before colors: mono, slate, warm, contrast, ocean, dusk, forest, ember or rose. mono is the stylesheet default and emits nothing.
colors{ light?: Partial<ThemeColors>; dark?: Partial<ThemeColors> }-Colour token overrides per scheme. Only the keys you set are emitted.
code{ light?: Partial<CodeTokenColors>; dark?: Partial<CodeTokenColors> }-Token group overrides for the bundled code themes. Ignored when codeTheme is a custom pair.
codeTheme"pzza" | { light: ThemeRegistration; dark: ThemeRegistration }"pzza"The bundled subdued pair, or any two shiki theme registrations, for example objects imported from shiki/themes.
radiusnumber | string4Corner radius for every control. Numbers are pixels. Also derives --pd-radius-sm as max(2px, calc(radius - 1px)).
fontsThemeFonts-font-family values for text and code.
layoutThemeLayout-Sidebar, TOC, content and header sizes.
density"comfortable" | "compact""comfortable"Row heights and paddings. comfortable matches the stylesheet defaults and emits nothing.

ResolvedThemeConfig#

ts
interface ResolvedThemeConfig extends ThemeConfig {
  defaultTheme: "light" | "dark" | "system";
  hotKey: boolean;
  preset: ThemePreset;
  codeTheme: "pzza" | CodeThemePair;
  density: ThemeDensity;
}

ThemeColors#

One key per colour token. Any CSS colour string is accepted and used as written.

KeyTokenUsed for
background--pd-backgroundPage and header background.
surface--pd-surfaceCards, code blocks, dialogs, buttons.
surface2--pd-surface-2Hover states, code block headers, inline code, callouts.
surface3--pd-surface-3Active sidebar item, selected search row, highlighted code lines.
foreground--pd-foregroundPrimary text and active states.
foreground2--pd-foreground-2Secondary text, callout bodies.
mutedForeground--pd-muted-foregroundDescriptions, nav tabs, TOC, section labels.
faintForeground--pd-faint-foregroundPlaceholders, line numbers, separators.
border--pd-borderEvery default border.
borderStrong--pd-border-strongHovered card borders, link underlines, word highlights.
sidebar--pd-sidebarSidebar background.
ring--pd-ringFocus ring.
overlay--pd-overlayBackdrop behind the search dialog, mobile drawer and image zoom.
accent--pd-accentProse links, the active header tab underline, active tab and code tab underlines. Equals foreground in the gray presets.
accentForeground--pd-accent-foregroundText on an accent background.

Preset values for each key are listed on the Presets page.

CodeTokenColors#

Token groups of the bundled pzza-light and pzza-dark themes. Each key maps to a set of TextMate scopes; the defaults below are what codeTheme: "pzza" ships with.

KeyScopesLightDark
plainSource text and the theme foreground.#111111#ececec
keywordKeywords, storage, control flow, new, typeof; also bold headings in Markdown.#5b4bb5#b4a4f5
fnFunction and method names, calls.#2f5fa6#8db4f0
stringStrings, template literals, inline code in Markdown.#3b7f5c#8fc9a6
numberNumbers, booleans, language constants.#a8632a#e0a874
typeTypes, classes, interfaces, namespaces.#22768a#7fc3cf
tagHTML and JSX tags, components.#a8403a#e39a93
attributeTag attribute names.#6a6a6a#c4c4c4
propertyObject keys, YAML keys, JSON and CSS property names.#3d3d3d#d8d8d8
variableVariables and parameters.#111111#ececec
commentComments (rendered italic).#9a9a9a#6a6a6a
punctuationOperators, braces, separators.#6a6a6a#8a8a8a
regexRegular expressions.#3b7f5c#8fc9a6
templatePunctuation${ and } in template literals, embedded sections.#5b4bb5#b4a4f5
backgroundCode block background.#ffffff#121212

CodeThemePair#

ts
interface CodeThemePair {
  light: ThemeRegistration;
  dark: ThemeRegistration;
}

ThemeRegistration is the shiki theme object type. Both themes are loaded into the highlighter and every token carries both colours as CSS variables, so switching schemes does not re-highlight anything.

ThemeFonts#

NameTypeDefaultDescription
sansstring-font-family for text and UI, written to --pd-font-sans. For next/font pass the published variable, for example var(--font-geist-sans), system-ui, sans-serif.
monostring-font-family for code, written to --pd-font-mono.

ThemeLayout#

Numbers are pixels; strings are used verbatim.

NameTypeDefaultDescription
sidebarWidthnumber | string240pxDesktop sidebar width, written to --pd-sidebar-width.
tocWidthnumber | string220pxRight-hand TOC column width, written to --pd-toc-width.
contentWidthnumber | string72chMaximum article width, written to --pd-content-width.
headerHeightnumber | string48pxHeader height, written to --pd-header-height. Sticky offsets derive from it.

Design tokens#

Every custom property the stylesheet reads. Colour defaults are the mono preset.

Colour tokens#

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

Shape, size and motion tokens#

TokenDefaultDescription
--pd-radius4pxBorder radius for cards, code blocks, buttons, tabs and dialogs. Set by theme.radius.
--pd-radius-sm3pxRadius for inline code, kbd and word highlights. Derived from theme.radius as max(2px, calc(radius - 1px)).
--pd-header-height48pxHeader height. Set by theme.layout.headerHeight.
--pd-banner-height0pxSet by Banner while it is visible.
--pd-sidebar-width240pxDesktop sidebar width. Set by theme.layout.sidebarWidth.
--pd-toc-width220pxTOC column width. Set by theme.layout.tocWidth.
--pd-content-width72chMaximum article width. Set by theme.layout.contentWidth.
--pd-content-max-widthcalc(76ch + 260px + 48px)Maximum width of the whole layout row.
--pd-transition120ms easeDuration and easing for hover and open transitions. 0ms under reduced motion.
--pd-font-sansGeist, ui-sans-serif, system-ui, sans-serifBody and UI font. Set by theme.fonts.sans.
--pd-font-mono"Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospaceCode font. Set by theme.fonts.mono.

Density tokens#

Emitted only for density: "compact"; the comfortable values are the stylesheet defaults.

TokenComfortableCompact
--pd-row-height28px24px
--pd-block-gap16px12px
--pd-cell-padding-block8px5px
--pd-cell-padding-inline12px10px
--pd-box-padding-block10px8px
--pd-box-padding-inline12px10px
--pd-card-padding14px 16px10px 12px

ThemeStyles#

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

function ThemeStyles({ theme }: { theme: ResolvedThemeConfig }): JSX.Element | null;

A server component that renders a <style> element with the output of resolveThemeCss(theme). RootProvider renders it for you; include it yourself only when you build a custom provider. Pass config.theme from your defineConfig result.

app/layout.tsx
import { ThemeStyles } from "pzzadocs/ui";
import config from "@/docs.config";

<ThemeStyles theme={config.theme} />

resolveThemeCss#

ts
import { resolveThemeCss } from "pzzadocs";

function resolveThemeCss(theme: ResolvedThemeConfig): string;

Returns the CSS text ThemeStyles emits: a :root { ... } block followed by a .dark, [data-theme="dark"] { ... } block, each omitted when empty. The empty string means the config changes nothing. Resolution order:

  1. The preset expands to all thirteen colour tokens for both schemes, unless it is mono.
  2. colors.light and colors.dark are layered on top, key by key.
  3. radius writes --pd-radius and the derived --pd-radius-sm.
  4. fonts and layout write their tokens; numbers become px.
  5. density: "compact" appends the compact density tokens.

String values have ;, { and } stripped so a value cannot break out of its declaration. This is a server entry; use it to inline the CSS somewhere other than ThemeStyles, for example in a static export or an email-safe preview.