> ## Documentation Index
> Fetch the complete documentation index at: https://docs.olonjs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Customize your OlonJS site theme with design tokens

> Customize your OlonJS site's colors, typography, spacing, and dark mode by editing the theme.json design token file — no CSS changes required.

OlonJS drives all visual styling through a design token system defined in `src/data/config/theme.json`. Changing a token updates every component that uses it — including both dark mode (the default) and light mode. You never need to touch a CSS file or a component to retheme your site.

<Warning>
  `public/config/site.json` is auto-generated by the build step. Always edit `src/data/config/theme.json` — changes to the `public/` file will be overwritten the next time you run `npm run build`.
</Warning>

***

## The theme.json file

The theme file has a `name` field and a `tokens` object that groups all design decisions:

```json src/data/config/theme.json theme={null}
{
  "name": "Inkwell Journal",
  "tokens": {
    "colors": { ... },
    "typography": { ... },
    "borderRadius": { ... },
    "spacing": { ... },
    "zIndex": { ... },
    "modes": {
      "light": {
        "colors": { ... }
      }
    }
  }
}
```

| Top-level key | What it controls |
| - | - |
| `tokens.colors` | Base (dark mode) color palette |
| `tokens.typography` | Font families and wordmark settings |
| `tokens.borderRadius` | Corner radius scale |
| `tokens.spacing` | Layout dimensions (container width, section padding, etc.) |
| `tokens.zIndex` | Stacking order scale |
| `tokens.modes.light.colors` | Light mode color overrides |

***

## Color tokens

OlonJS uses semantic color naming — each token name describes the role, not the literal hue. This means you can swap the entire palette by editing `tokens.colors` without hunting for hardcoded hex values inside components.

| Token | Role |
| - | - |
| `background` | Page background |
| `foreground` | Default body text |
| `primary` | Brand accent — buttons, links, highlights |
| `primary-foreground` | Text on top of `primary` surfaces |
| `accent` | Secondary brand color for chips, badges |
| `secondary` | Subtle surface color for cards and sidebar items |
| `muted` | Low-contrast background for hover states and dividers |
| `border` | Default border color |
| `destructive` | Error and destructive-action color |
| `success` | Success and confirmation color |
| `warning` | Warning and caution color |
| `info` | Informational color |

The Inkwell theme also defines extended tokens like `card`, `elevated`, `overlay`, `ring`, `primary-light`, `primary-dark`, and `*-foreground` variants for each semantic color. You can add as many tokens as your design system needs.

***

## Updating a color

To change the brand color, edit the `primary` token in `tokens.colors`:

```json Before theme={null}
"primary": "#e0745c"
```

```json After theme={null}
"primary": "#5b8dee"
```

Then rebuild to apply the change everywhere:

```bash theme={null}
npm run build
```

Because every component references `var(--color-primary)` rather than a hardcoded value, the update propagates across all buttons, links, chips, and highlighted text in one edit.

***

## Light mode override

`tokens.modes.light.colors` overrides any base token when the visitor's theme is set to light. The default mode is dark; light mode is activated when `document.documentElement.dataset.theme === 'light'`.

The light palette in Inkwell replaces every color token with a lighter counterpart:

```json src/data/config/theme.json (excerpt) theme={null}
{
  "tokens": {
    "modes": {
      "light": {
        "colors": {
          "background": "#faf8f4",
          "foreground": "#1d1c1a",
          "card": "#ffffff",
          "primary": "#c1543c",
          "primary-foreground": "#fdf6f3",
          "accent": "#4a66b0",
          "muted": "#f0ede5",
          "border": "#e0dcd1"
        }
      }
    }
  }
}
```

You only need to list the tokens you want to override — any token not listed in `modes.light.colors` falls back to its base value.

<Tip>
  To switch a user's theme at runtime, toggle `document.documentElement.dataset.theme` between `'light'` and `''` (or `'dark'`). OlonJS picks up the change via CSS attribute selectors without a page reload.
</Tip>

***

## Typography tokens

Control font families for body text, code, display headings, and the site wordmark:

```json src/data/config/theme.json (excerpt) theme={null}
{
  "tokens": {
    "typography": {
      "fontFamily": {
        "primary": "'Instrument Sans', system-ui, sans-serif",
        "mono": "'JetBrains Mono', monospace",
        "display": "'Bricolage Grotesque', system-ui, sans-serif"
      },
      "wordmark": {
        "fontFamily": "'Bricolage Grotesque', system-ui, sans-serif",
        "weight": "800"
      }
    }
  }
}
```

| Token | Used for |
| - | - |
| `fontFamily.primary` | Body text, UI labels, navigation |
| `fontFamily.mono` | Code blocks and inline code |
| `fontFamily.display` | Hero headings and section titles |
| `wordmark.fontFamily` | Site name in the header logo |
| `wordmark.weight` | Font weight for the site name |

To swap fonts, replace the font-family strings and add the corresponding `@import` or `<link>` to your Next.js layout.

***

## Spacing and border radius

### Spacing tokens

These control macro layout dimensions shared across all sections:

| Token | Default | Controls |
| - | - | - |
| `container-max` | `1200px` | Maximum width of the content container |
| `section-y` | `96px` | Default vertical padding for sections |
| `header-h` | `80px` | Height reserved for the sticky header |
| `sidebar-w` | `240px` | Width of the Studio sidebar panel |

### Border radius tokens

| Token | Default | Used for |
| - | - | - |
| `sm` | `4px` | Badges, small chips |
| `md` | `8px` | Buttons, inputs |
| `lg` | `14px` | Cards |
| `xl` | `20px` | Large modals and panels |
| `full` | `9999px` | Pill shapes (tags, avatars) |

Adjust these tokens to shift the overall "roundness" of the UI — for example, setting all values to `0` produces a sharp, editorial look, while larger values create a softer, app-like feel.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.