theme.json colour, type and spacing presets
A compact theme.json that defines a palette, fluid font sizes, a spacing scale and element styles for the block editor.
WordPressThemingtheme-jsonblock-themedesign-tokensfse
Code
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"appearanceTools": true,
"layout": { "contentSize": "720px", "wideSize": "1200px" },
"color": {
"defaultPalette": false,
"palette": [
{ "slug": "base", "name": "Base", "color": "#ffffff" },
{ "slug": "contrast", "name": "Contrast", "color": "#10231f" },
{ "slug": "primary", "name": "Primary", "color": "#0f766e" },
{ "slug": "accent", "name": "Accent", "color": "#e9a23b" },
{ "slug": "surface", "name": "Surface", "color": "#f1f5f4" }
]
},
"typography": {
"fluid": true,
"fontFamilies": [
{
"slug": "body",
"name": "System sans",
"fontFamily": "system-ui, -apple-system, 'Segoe UI', sans-serif"
},
{
"slug": "display",
"name": "System serif",
"fontFamily": "Georgia, 'Times New Roman', serif"
}
],
"fontSizes": [
{ "slug": "small", "name": "Small", "size": "0.875rem" },
{ "slug": "medium", "name": "Medium", "size": "1.125rem", "fluid": { "min": "1rem", "max": "1.25rem" } },
{ "slug": "large", "name": "Large", "size": "1.75rem", "fluid": { "min": "1.4rem", "max": "2.1rem" } },
{ "slug": "x-large", "name": "Extra large", "size": "2.75rem", "fluid": { "min": "2rem", "max": "3.5rem" } }
]
},
"spacing": {
"spacingScale": { "steps": 0 },
"spacingSizes": [
{ "slug": "20", "name": "S", "size": "0.75rem" },
{ "slug": "40", "name": "M", "size": "1.5rem" },
{ "slug": "60", "name": "L", "size": "clamp(2rem, 4vw, 3.5rem)" },
{ "slug": "80", "name": "XL", "size": "clamp(3rem, 8vw, 7rem)" }
]
}
},
"styles": {
"color": { "background": "var(--wp--preset--color--base)", "text": "var(--wp--preset--color--contrast)" },
"typography": { "fontFamily": "var(--wp--preset--font-family--body)", "fontSize": "var(--wp--preset--font-size--medium)", "lineHeight": "1.65" },
"elements": {
"link": {
"color": { "text": "var(--wp--preset--color--primary)" },
":hover": { "typography": { "textDecoration": "none" } }
},
"heading": {
"typography": { "fontFamily": "var(--wp--preset--font-family--display)", "lineHeight": "1.15" }
},
"button": {
"color": { "background": "var(--wp--preset--color--primary)", "text": "var(--wp--preset--color--base)" },
"border": { "radius": "999px" }
}
},
"blocks": {
"core/group": { "spacing": { "padding": { "top": "var(--wp--preset--spacing--60)", "bottom": "var(--wp--preset--spacing--60)" } } }
}
}
}
How it works
What it solves
Design tokens scattered across stylesheets drift apart and cannot be reached from the editor. A single theme.json publishes colours, font sizes and spacing as presets, so editors pick from the same scale the stylesheet uses.
How it works
Each preset becomes a CSS custom property such as --wp--preset--color--primary, and WordPress also generates utility classes for them. Setting defaultPalette to false hides the stock colours so only brand colours appear in the picker. Font sizes use the fluid option, which emits clamp() values that scale between the stated minimum and maximum without media queries.
The styles section then applies the tokens to the body, links, headings, buttons and the group block, so a fresh page already looks designed.
Adapting it
Replace the hex values and font stacks, keep the slugs stable because saved content references them. Add templateParts and customTemplates entries when you ship templates. For a classic theme this file still works: it drives editor colours and spacing controls. Self-hosted fonts go through fontFace entries under each family.
Pitfalls
- A trailing comma or a comment makes the whole file invalid, and the editor silently falls back to defaults.
- Renaming a slug orphans blocks that used it.
spacingScale.steps: 0is required when you supply your ownspacingSizes.- Keep contrast ratios checked; a palette is not accessible by default.
How to use it
Place the file at the theme root next to style.css.
Open the Site Editor, then Styles, to see the palette, type scale and spacing sizes.
Use tokens in CSS with var(--wp--preset--color--accent) or var(--wp--preset--spacing--40).
Validate the JSON with any linter before shipping.
Licence: GPL-2.0-or-later. This snippet comes from WordPress code and is GPL-2.0-or-later.