Design Tokens
Design tokens define your ClearCMS site's visual language -- colors, fonts, spacing, radii, and shadows. They're stored as CSS custom properties (e.g. --theme-primary) and used by every section.
When building a custom frontend with Bridge Mode or the Headless API, fetch these tokens to stay in sync with the ClearCMS editor.
Try it — live token customizer
Change colors below and watch the section update in real time. One change propagates everywhere.
View generated CSS
:root {
--theme-primary: #2563eb;
--theme-secondary: #7c3aed;
--theme-text: #111827;
--theme-bg: #ffffff;
--theme-bg-alt: #f9fafb;
--theme-border: #e5e7eb;
}Public endpoints
All public endpoints require no API key, support CORS, and are cached for 1 hour. They return published branding values only.
Get tokens as JSON
GET /api/v1/public/tokens.json
Returns tokens organized by category. Category keys have the --theme- prefix stripped. The raw object preserves full CSS variable names.
Response:
{
"colors": {
"primary": "#2563eb",
"primary-hover": "#1d4ed8",
"primary-light": "#dbeafe",
"secondary": "#7c3aed",
"secondary-hover": "#6d28d9",
"text": "#111827",
"text-muted": "#4b5563",
"text-on-primary": "#ffffff",
"bg": "#ffffff",
"bg-alt": "#f9fafb",
"bg-muted": "#f3f4f6",
"border": "#e5e7eb",
"border-strong": "#d1d5db"
},
"fonts": {
"font-sans": "Inter, sans-serif",
"font-heading": "Inter, sans-serif"
},
"spacing": {},
"radius": {},
"shadows": {},
"headings": {},
"layout": {},
"raw": {
"--theme-primary": "#2563eb",
"--theme-primary-hover": "#1d4ed8",
"--theme-text": "#111827",
"--theme-font-sans": "Inter, sans-serif"
}
}
The raw object contains every token with its full --theme-* name. Categorized objects use shortened keys (e.g. "primary" instead of "--theme-primary").
Empty categories return {}. Spacing, radius, shadows, and headings populate when you configure those values via branding or token overrides.
Get tokens as CSS
GET /api/v1/public/tokens.css
Returns all tokens as CSS custom properties:
Response:
html:root {
--theme-primary: #2563eb;
--theme-primary-hover: #1d4ed8;
--theme-primary-light: #dbeafe;
--theme-secondary: #7c3aed;
--theme-text: #111827;
--theme-text-muted: #4b5563;
--theme-bg: #ffffff;
--theme-bg-alt: #f9fafb;
--theme-border: #e5e7eb;
--theme-font-sans: Inter, sans-serif;
--theme-font-heading: Inter, sans-serif;
/* ... all active --theme-* variables */
}
Values are sanitized: url(), expression(), javascript:, @import, and injection attempts are stripped.
Get tokens as Tailwind config
GET /api/v1/public/tailwind.config.js
Returns a Tailwind CSS config module with tokens mapped to theme.extend keys (colors, fontFamily, borderRadius, boxShadow, spacing, fontSize, fontWeight, lineHeight, letterSpacing, maxWidth). Use as a Tailwind v3 preset or fetch at build time for v4.
Response (JavaScript module):
/**
* ClearCMS Tailwind Config — auto-generated from site branding tokens.
*
* Usage (Tailwind v3):
* const clearcms = require("./clearcms-tailwind.config");
* module.exports = { presets: [clearcms] };
*/
module.exports = {
theme: {
extend: {
colors: {
"primary": "#2563eb",
"primary-hover": "#1d4ed8",
"secondary": "#7c3aed",
"text": "#111827",
"bg": "#ffffff",
// ... all color tokens
},
fontFamily: {
"sans": ["Inter", "ui-sans-serif", "system-ui", "sans-serif"],
"heading": ["Inter", "ui-sans-serif", "system-ui", "sans-serif"],
},
// borderRadius, boxShadow, spacing, fontSize, etc.
},
},
};
This is the fastest way to keep a Tailwind-based frontend in sync with ClearCMS branding. Values reflect the merged cascade: defaults, then branding, then token overrides.
Using tokens in a custom frontend
Option 1: Load as CSS
Add the tokens stylesheet to your HTML head:
<link
rel="stylesheet"
href="https://your-site.clearcms.app/api/v1/public/tokens.css"
/>
Then use the variables in your CSS:
h1 {
color: var(--theme-primary);
font-family: var(--theme-font-heading);
}
.card {
border: 1px solid var(--theme-border);
background: var(--theme-bg-alt);
}
Option 2: Fetch as JSON
For build-time or JavaScript access:
const res = await fetch(
"https://your-site.clearcms.app/api/v1/public/tokens.json"
);
const tokens = await res.json();
// Categorized keys are stripped — use "primary", not "--theme-primary"
const primaryColor = tokens.colors["primary"];
const fontFamily = tokens.fonts["font-sans"];
// Or use the raw object for full CSS variable names
const rawPrimary = tokens.raw["--theme-primary"];
Option 3: Use with Tailwind CSS
Fetch the pre-built Tailwind config from the public endpoint:
// 1. Fetch at build time (e.g. in a script or CI step)
// curl https://your-site.clearcms.app/api/v1/public/tailwind.config.js -o clearcms-tailwind.config.js
// 2. Use as a preset in tailwind.config.js
const clearcms = require("./clearcms-tailwind.config");
module.exports = { presets: [clearcms] };
Or map CSS variables manually if you load the tokens CSS file alongside Tailwind:
// tailwind.config.js
export default {
theme: {
extend: {
colors: {
primary: "var(--theme-primary)",
"primary-hover": "var(--theme-primary-hover)",
secondary: "var(--theme-secondary)",
},
fontFamily: {
sans: "var(--theme-font-sans)",
heading: "var(--theme-font-heading)",
},
},
},
};
Either approach lets you use Tailwind classes like text-primary and bg-secondary.
Token cascade
Tokens resolve in this order (later values win):
- Package defaults -- built-in fallbacks for colors, text, and backgrounds
- Branding -- derived from your site's branding settings (colors and fonts in the editor)
- Token overrides -- manual values set in Settings > Design > Tokens
Setting a primary brand color auto-generates --theme-primary-hover (10% darker) and --theme-primary-light (90% lighter).
Manual overrides always win. If you override --theme-primary in token settings, changing the branding primary color has no effect until you remove the override.
Typography scale
Set --theme-type-scale to a ratio (1--2) and ClearCMS generates text sizes from --theme-text-xs through --theme-text-6xl, plus heading sizes --theme-h1-size through --theme-h6-size.
Example: --theme-type-scale: 1.25 ("Major Third") with a 16px base produces:
| Token | Size |
|---|---|
--theme-text-xs | 0.64rem |
--theme-text-sm | 0.80rem |
--theme-text-base | 1rem |
--theme-text-lg | 1.25rem |
--theme-text-xl | 1.5625rem |
--theme-text-2xl | 1.9531rem |
--theme-text-3xl | 2.4414rem |
--theme-text-4xl | 3.0518rem |
--theme-text-5xl | 3.8147rem |
--theme-text-6xl | 4.7684rem |
Heading tokens map automatically: --theme-h1-size = --theme-text-6xl, --theme-h2-size = --theme-text-5xl, down to --theme-h6-size = --theme-text-xl.
Set via the token management API:
PATCH /api/v1/settings/tokens
{
"tokens": {
"--theme-type-scale": "1.25"
}
}
Common ratios: 1.125 (Major Second), 1.2 (Minor Third), 1.25 (Major Third), 1.333 (Perfect Fourth), 1.5 (Perfect Fifth). Generated sizes are clamped between 12px and 72px.
--theme-type-scale is not emitted as a CSS variable -- it's consumed during generation and replaced by individual size tokens.
Default tokens
Built-in defaults before branding or overrides:
| Token | Default | Purpose |
|---|---|---|
--theme-primary | #2563eb | Primary brand color |
--theme-primary-hover | #1d4ed8 | Primary hover state |
--theme-primary-light | #dbeafe | Light primary (backgrounds, badges) |
--theme-secondary | #7c3aed | Secondary accent color |
--theme-secondary-hover | #6d28d9 | Secondary hover state |
--theme-text | #111827 | Main body text |
--theme-text-muted | #4b5563 | Subdued text (captions, help text) |
--theme-text-on-primary | #ffffff | Text on primary-colored backgrounds |
--theme-bg | #ffffff | Page background |
--theme-bg-alt | #f9fafb | Alternate background (alternating sections) |
--theme-bg-muted | #f3f4f6 | Muted background (cards, inputs) |
--theme-border | #e5e7eb | Standard border color |
--theme-border-strong | #d1d5db | Emphasized border color |
Additional tokens (spacing, radius, shadows, headings, layout) have no defaults -- they populate when configured through branding or token overrides.
Branding-to-token mapping
Colors and fonts set in the branding editor map to tokens:
| Branding field | Token(s) generated |
|---|---|
| Primary color | --theme-primary, --theme-primary-hover, --theme-primary-light |
| Secondary color | --theme-secondary, --theme-secondary-hover |
| Accent color | Maps to --theme-secondary if no secondary is set |
| Background | --theme-bg |
| Surface | --theme-bg-alt, --theme-bg-muted |
| Dark | --theme-bg-dark |
| Text color | --theme-text |
| Muted text | --theme-text-muted |
| Border color | --theme-border |
| Header background | --theme-header-bg |
| Footer background | --theme-footer-bg |
| Heading font | --theme-font-heading |
| Body font | --theme-font-sans |
| H1–H6 styles | --theme-h1-size, --theme-h1-weight, etc. |
Token management (authenticated)
Require authentication with settings:modify permission.
Get current tokens
GET /api/v1/settings/tokens
Returns current token overrides and valid token names:
{
"tokens": {
"--theme-primary": "#ff0000"
},
"validTokens": ["--theme-primary", "--theme-secondary", "..."]
}
Update tokens (merge)
PATCH /api/v1/settings/tokens
Merges provided tokens with existing overrides:
{
"tokens": {
"--theme-primary": "#ff0000",
"--theme-bg": "#fafafa"
}
}
Replace all tokens
PUT /api/v1/settings/tokens
Replaces all token overrides entirely. Any tokens not included are removed.
Reset tokens
DELETE /api/v1/settings/tokens
Removes all manual overrides, reverting to branding and default values.
Simple vs Advanced mode
The branding editor has two modes controlling how many tokens you can set directly.
Simple mode
You set two values:
- Primary color — your main brand color
- Light/dark toggle — light background (
#ffffff) or dark background (#111827)
ClearCMS derives everything else:
| Derived token | How it's calculated |
|---|---|
| Secondary | Primary hue shifted +30° (analogous color) |
| Primary hover | Primary darkened by ~10% |
| Primary light | Primary at ~90% lightness |
| Text color | Dark text on light backgrounds, white text on dark backgrounds |
| Text-on-primary | White or dark text, whichever has better contrast against primary |
All derived colors meet WCAG 2.1 contrast requirements (4.5:1 for normal text).
Advanced mode
Gives you individual control over every color:
| Field | Token(s) |
|---|---|
| Primary | --theme-primary, auto-generates hover and light variants |
| Secondary | --theme-secondary, auto-generates hover variant |
| Accent | Maps to secondary if no secondary is set |
| Background | --theme-bg |
| Surface | --theme-bg-alt, --theme-bg-muted |
| Dark | --theme-bg-dark |
| Text | --theme-text |
| Muted text | --theme-text-muted |
| Border | --theme-border |
| Header background | --theme-header-bg |
| Footer background | --theme-footer-bg |
Even in Advanced mode, text-on-primary, text-on-secondary, and text-on-dark colors are auto-calculated for WCAG compliance.
Full token reference
Color tokens
| Token | Default | Purpose |
|---|---|---|
--theme-primary | #2563eb | Primary brand color |
--theme-primary-hover | #1d4ed8 | Primary hover state |
--theme-primary-light | #dbeafe | Light primary (backgrounds, badges) |
--theme-secondary | #7c3aed | Secondary accent color |
--theme-secondary-hover | #6d28d9 | Secondary hover state |
--theme-text | #111827 | Main body text |
--theme-text-muted | #4b5563 | Subdued text (captions, help text) |
--theme-text-light | #9ca3af | Decorative text |
--theme-text-on-primary | #ffffff | Text on primary-colored backgrounds |
--theme-text-on-secondary | #ffffff | Text on secondary-colored backgrounds |
--theme-text-on-dark | #ffffff | Text on dark backgrounds |
--theme-text-on-dark-muted | rgba(255,255,255,0.7) | Secondary text on dark backgrounds |
--theme-bg | #ffffff | Page background |
--theme-bg-alt | #f9fafb | Alternate background (alternating sections) |
--theme-bg-muted | #f3f4f6 | Muted background (cards, inputs) |
--theme-bg-dark | #111827 | Dark sections and footers |
--theme-border | #e5e7eb | Standard border color |
--theme-border-strong | #d1d5db | Emphasized border color |
--theme-header-bg | (inherits --theme-bg) | Navbar/header background |
--theme-footer-bg | #1e293b | Footer background |
--theme-success | #059669 | Success messages |
--theme-warning | #d97706 | Warning messages |
--theme-error | #dc2626 | Error messages |
--theme-info | #0284c7 | Informational messages |
Typography tokens
| Token | Default | Purpose |
|---|---|---|
--theme-font-sans | System UI stack | Body text font family |
--theme-font-heading | System UI stack | Heading font family |
--theme-font-mono | Cascadia Code, Fira Code | Code and monospace text |
--theme-text-xs | 0.75rem | Minimum readable text |
--theme-text-sm | 0.875rem | Small text |
--theme-text-base | 1rem | Body text baseline |
--theme-text-lg | 1.125rem | Large body text |
--theme-text-xl – 6xl | 1.25rem – 3.75rem | Heading scale |
--theme-h1-size – h6-size | 3.75rem – 1.25rem | Per-heading size override |
--theme-h1-weight – h6-weight | 700 – 600 | Per-heading weight |
--theme-h1-line-height – h6-line-height | 1.1 – 1.4 | Per-heading line height |
Spacing tokens
| Token | Default | Purpose |
|---|---|---|
--theme-section-y | 4rem | Vertical section padding |
--theme-container-x | 1rem | Horizontal container padding |
--theme-card-padding | 1.5rem | Card internal padding |
--theme-card-gap | 1.5rem | Gap between cards |
--theme-button-y | 8px | Button vertical padding |
--theme-button-x | 16px | Button horizontal padding |
--theme-input-y | 8px | Input vertical padding |
--theme-input-x | 12px | Input horizontal padding |
--theme-gap | 16px | General content gap |
--theme-padding | 24px | General content padding |
Spacing presets (set in branding):
| Preset | Section Y | Gap | Padding |
|---|---|---|---|
| Compact | 40px | 12px | 16px |
| Normal (default) | 64px | 16px | 24px |
| Spacious | 96px | 24px | 32px |
Border radius tokens
| Token | Default | Purpose |
|---|---|---|
--theme-radius | 8px | Global radius |
--theme-button-radius | 6px | Button corners |
--theme-card-radius | 8px | Card corners |
--theme-input-radius | 6px | Input corners |
--theme-badge-radius | 9999px | Badge/pill corners |
Radius presets: Sharp (2px), Rounded (8px, default), Pill (9999px), or a custom value.
Shadow tokens
| Token | Default | Purpose |
|---|---|---|
--theme-shadow-sm | 0 1px 2px rgba(0,0,0,0.05) | Subtle depth |
--theme-shadow-md | 0 4px 6px rgba(0,0,0,0.1) | Standard shadow |
--theme-shadow-lg | 0 10px 15px rgba(0,0,0,0.1) | Prominent depth |
--theme-card-shadow | (mirrors shadow-md) | Card shadows |
--theme-button-shadow | (mirrors shadow-sm) | Button shadows |
The shadow-sm, shadow-md, and shadow-lg tokens are CSS defaults defined in the stylesheet. They cannot be overridden via the token management API. Only card-shadow and button-shadow are configurable through token overrides.
Layout tokens
| Token | Default | Purpose |
|---|---|---|
--theme-container-max | 1280px | Max site content width |
--theme-content-max | 65ch | Optimal prose reading width |
Available token categories
| Category | Key pattern | Example tokens |
|---|---|---|
| Colors | primary*, secondary*, text*, bg*, border*, success, warning, error, info | --theme-primary, --theme-bg-alt, --theme-border-strong |
| Fonts | font-* | --theme-font-sans, --theme-font-heading, --theme-font-mono |
| Spacing | section-*, container-*, button-*, input-*, card-* | --theme-section-y, --theme-card-padding |
| Radius | Contains radius | --theme-radius, --theme-card-radius |
| Shadows | Contains shadow | --theme-card-shadow, --theme-button-shadow |
| Headings | h1-* through h6-* | --theme-h1-size, --theme-h2-weight, --theme-h3-line-height |
| Layout | content-*, hero-*, image-* | --theme-content-max, --theme-hero-image-max |
Only --theme--prefixed tokens are accepted. The system validates against ~90 known token names. Invalid names are silently stripped.