Theme reference

What `SiteConfig.theme` controls — primary color, font family, corner radius — and how it composes with route-level overrides.

Every Linkfor site stores its visual settings in a single theme object on SiteConfig. The dashboard's Settings → Theme tab is the GUI; this page documents the underlying fields so you know exactly what each control changes on the rendered page.

The shape

type SiteTheme = {
  primaryColor?: string  // any valid CSS color
  fontFamily?: string    // any valid CSS font stack
  cornerRadius?: string  // any valid CSS length (px, rem, em)
}

All three fields are optional. Anything left blank falls back to the built-in defaults: a near-black oklch(0.2 0.006 75) ink color, the system sans stack with Inter as the preferred face, and a 6px corner radius on cards / buttons.

primaryColor

Drives the link color, focus ring, button background, and progress / loading indicators on rendered pages. Typed as a free-form CSS string, so any of these are valid:

#3b82f6
rgb(59 130 246)
oklch(0.6 0.18 250)
hsl(217 91% 60%)
royalblue

The dashboard ships a small swatch picker for the most common cases; the underlying input takes any CSS color you can write by hand.

We deliberately don't restrict the input to a palette — sites that match an existing brand should be able to paste their exact hex.

fontFamily

Replaces the body font stack on the rendered tenant page. Any valid CSS font stack works:

"Inter", system-ui, sans-serif
"Iowan Old Style", Palatino, serif
"JetBrains Mono", ui-monospace, monospace

If you reference a custom font, make sure it's available — either host it yourself and @import from Notion's HTML embed (custom domain only, see the embed docs in the dashboard) or pick a stack that the visitor's OS already has.

The marketing surface, dashboard, and platform admin all live on their own font stacks (Instrument Serif display, Inter sans, JetBrains Mono code) — fontFamily only affects the tenant render tree.

cornerRadius

Applied to cards, buttons, code blocks, and image frames on the rendered tenant page. Takes a CSS length:

0px      /* sharp corners */
6px      /* default */
12px     /* friendly */
9999px   /* pill — only sensible on small UI like badges */

Route-level overrides

Routes have their own theme field that, when set, overrides the site-level one for that path and everything beneath it in the route tree. Useful for, say, a marketing landing page that should be visually distinct from the rest of a docs site.

The dashboard exposes this as Settings → Theme (per-route) when you expand a route in the routes tree.

Where theme tokens live in the data model

// lib/db/schema.ts (excerpt)
sites: {
  theme: jsonb<SiteTheme>()
}

The same shape exists at the route level (tenantRoutes.theme). The walker that renders a page composes site-level → route-level so route settings only need to specify the fields that diverge from the site.

What's NOT themable (yet)

  • Header / navigation chrome — driven by nav config on the route, not theme.
  • Footer text — controlled by the Powered by Linkfor footer toggle (Business plan only) and the per-site footer field, not theme.
  • Notion's own block styling (callouts, toggles, columns) — we inherit react-notion-x's defaults; opening these up is on the roadmap as part of the link-in-bio editor work.
Add a screenshot of Settings → Theme showing the three fields and a live preview.