theme.json Generator
Build a block theme's theme.json: palette and font size presets, layout widths, spacing units and the style defaults, with the preset slugs checked.
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"appearanceTools": true,
"color": {
"custom": false,
"customGradient": false,
"defaultPalette": false,
"palette": [
{
"color": "#FFFFFF",
"name": "Base",
"slug": "base"
},
{
"color": "#111111",
"name": "Contrast",
"slug": "contrast"
},
{
"color": "#1E56EC",
"name": "Accent",
"slug": "accent"
}
]
},
"layout": {
"contentSize": "645px",
"wideSize": "1340px"
},
"spacing": {
"blockGap": true,
"margin": true,
"padding": true,
"units": [
"px",
"rem",
"vh",
"vw",
"%"
]
},
"typography": {
"customFontSize": false,
"defaultFontSizes": false,
"fluid": true,
"fontSizes": [
{
"name": "Small",
"size": "0.875rem",
"slug": "small"
},
{
"name": "Medium",
"size": "1rem",
"slug": "medium"
},
{
"name": "Large",
"size": "1.5rem",
"slug": "large"
},
{
"name": "X-Large",
"size": "2.25rem",
"slug": "x-large"
}
],
"lineHeight": true
},
"useRootPaddingAwareAlignments": true
},
"styles": {
"color": {
"background": "var(--wp--preset--color--base)",
"text": "var(--wp--preset--color--contrast)"
},
"spacing": {
"padding": {
"left": "1.5rem",
"right": "1.5rem"
}
},
"typography": {
"lineHeight": "1.6"
}
}
}
Output is valid and updates as you type.
Fix the highlighted fields to update the output.
Write a block theme’s theme.json: the presets editors pick from, the widths blocks align to, and the controls you want to leave them.
How to use
- Start with the format version. 3 is current and needs WordPress 6.6; pick 2 only if the site is older.
- Add your colours. Each row becomes an editor swatch and a
--wp--preset--color--<slug>custom property, so the slug is a public name: keep it short and do not rename it later. - Decide what you are taking away. Turning off custom colours and the WordPress palette is what makes a theme feel designed rather than configurable.
- Set the two widths. Content width is what a normal block gets; wide width is what the wide alignment stretches to.
- Add font sizes, then choose whether fluid typography turns each one into a
clamp(). Fluid is on by default here because it is the cheaper way to be responsive. - Copy the output to
theme.jsonin your theme folder. Reload the editor: presets appear immediately, no cache to clear.
Example
The defaults give a three colour theme with its own font sizes and nothing else offered:
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"appearanceTools": true,
"color": {
"custom": false,
"customGradient": false,
"defaultPalette": false,
"palette": [
{ "color": "#FFFFFF", "name": "Base", "slug": "base" },
{ "color": "#111111", "name": "Contrast", "slug": "contrast" },
{ "color": "#1E56EC", "name": "Accent", "slug": "accent" }
]
},
"layout": { "contentSize": "645px", "wideSize": "1340px" },
"useRootPaddingAwareAlignments": true
},
"styles": {
"color": {
"background": "var(--wp--preset--color--base)",
"text": "var(--wp--preset--color--contrast)"
}
}
}
The body colours point at the presets rather than repeating the hex, so changing the Base row changes the page background too.
Pitfalls
- Version 3 changed what a font size list means. In 2, declaring
fontSizesreplaced WordPress’s own; in 3 they are added to yours unlessdefaultFontSizesisfalse. The same applies to spacing sizes. - A child theme’s
theme.jsonoverrides the parent per key, not per value. Givesettings.color.paletteand you replace the parent’s entire palette, not just the colours you listed. - Preset slugs are part of your CSS API.
var(--wp--preset--color--accent)is what patterns, user styles and custom CSS refer to; renaming a slug breaks all of them silently. - A name with accents or non-Latin characters cannot become a slug on its own. Type the slug yourself for those rows, or you get the letters that survived.
useRootPaddingAwareAlignmentsonly does anything ifstyles.spacing.paddingis set. On its own it is inert.- Changes an editor makes in the Site Editor are stored in the database and win over the file. Your
theme.jsonedits will look ignored until those user styles are reset. settings.color.custom: falsehides the picker but does not remove colours already saved in content. Old posts keep their inline hex values.- Fluid typography rewrites every size, including ones you set with
clamp()yourself. Turn it off per preset, or leave your own clamp out of a fluid theme.
Compatibility
theme.json needs WordPress 5.8; schema version 2 needs 5.9 and version 3 needs 6.6. useRootPaddingAwareAlignments and fluid typography both arrived in 6.1. appearanceTools needs 6.0. defaultPalette has been available since 5.9, defaultFontSizes and defaultSpacingSizes since 6.6. Everything written here is plain JSON with no theme-specific keys, so it works in a parent or a child theme. The tool runs entirely in your browser.
Frequently asked questions
Where does the file go?
style.css. Block themes read it automatically; classic themes can use it too, for settings only.Why is my palette showing extra colours?
defaultPalette is on, so WordPress adds its own. Turn it off to offer only yours.Do I need styles as well as settings?
settings defines what is available, styles sets what is used. A theme can ship settings alone and let patterns do the rest.How do I check what WordPress made of it?
:root under --wp--preset--.