Theming

Brand your docs entirely from markline.json — logo, favicon, fonts, colors, and the full palette. No code to fork.

Everything visual is driven by the theme block (and a couple of topbar fields) in your config — no component overrides required.

The config file

Markline reads markline.json, falling back to docs.json so projects migrating from a docs.json config work unchanged.

All theming lives under theme in that file. Image paths (logo, favicon) are served from your project's public/ directory.

Default theme

theme.appearance"system" | "light" | "dark"

The default color scheme. "system" follows the OS (the default); set "dark" or "light" to force one. Visitors can still toggle, and their choice is remembered.

"theme": { "appearance": "dark" }   // open in dark mode by default

Logo & favicon

The logo can be an icon + wordmark (the common docs pattern), light/dark images, or just text.

theme.logo.iconstring
Small mark shown next to the name (e.g. /logo-mark.svg).
theme.logo.textstring
Wordmark text shown beside the icon (defaults to name).
theme.logo.light / theme.logo.darkstring
Full logo images, swapped by color scheme. Used when no icon is set.
theme.faviconstring
Favicon path, e.g. /favicon.svg.
"theme": {
  "logo": { "icon": "/logo-mark.svg", "text": "acme" },
  "favicon": "/favicon.svg"
}

Accent color

theme.colors.primarystring
Brand accent (hex) for light mode.
theme.colors.primaryDarkstring
Brand accent for dark mode (and hover).
"theme": { "colors": { "primary": "#4f46e5", "primaryDark": "#818cf8" } }

Using a light accent (e.g. lime or yellow)? White text on it is invisible. Set the on-accent text color with the --c-on-brand variable (see below) — it controls text/icons on brand-colored surfaces (buttons, badges, numbered cards).

Full palette

For deeper theming, override any CSS custom property via theme.cssVariables, split into light and dark. Color values are space-separated RGB triples (e.g. 247 246 241), not hex.

Always provide both light and dark if you customize the palette — otherwise dark mode falls back to Markline's default dark.

The tokens you'll reach for most:

TokenMeaning
--c-brand, --c-brand-deepAccent + hover (also set via colors)
--c-on-brandText/icon color on brand surfaces
--c-paper, --c-paper-2Page and raised surface backgrounds
--c-ink, --c-ink-soft, --c-ink-2, --c-ink-3Text shades
--c-slate-0--c-slate-8Neutral scale (borders, muted text)
"theme": {
  "cssVariables": {
    "light": {
      "--c-paper": "247 246 241",
      "--c-ink": "15 15 14",
      "--c-on-brand": "15 15 14"
    },
    "dark": {
      "--c-paper": "18 18 14",
      "--c-ink": "232 231 224",
      "--c-on-brand": "15 15 14"
    }
  }
}

Fonts

theme.font.sans / theme.font.monostring

Font-family overrides. The font must be system-available or self-loaded (e.g. via a @font-face in a stylesheet you include). Defaults to Geist.

"theme": { "font": { "sans": "Inter", "mono": "JetBrains Mono" } }

Label pill

topbar.badgestring

A small bordered pill shown next to the logo — handy for a version or status label, e.g. "docs · v1" or "beta".

Worked example

A complete warm, lime-accented theme that defaults to dark:

{
  "name": "acme",
  "theme": {
    "appearance": "dark",
    "logo": { "icon": "/mark.svg", "text": "acme" },
    "favicon": "/mark.svg",
    "colors": { "primary": "#D7FC50", "primaryDark": "#C2E63D" },
    "cssVariables": {
      "light": { "--c-on-brand": "15 15 14", "--c-paper": "247 246 241", "--c-ink": "15 15 14" },
      "dark":  { "--c-on-brand": "15 15 14", "--c-paper": "18 18 14",  "--c-ink": "232 231 224" }
    }
  },
  "topbar": { "badge": "docs · v1" }
}
Changing theme values takes effect on the next markline dev reload — no rebuild of the framework, ever.