Style variations

In previous lessons I have talked about theme.json as a single configuration file for your theme, but you can use multiple JSON files to add alternative settings and global style variations. This feature has been available since WordPress version 6.0, so chances are that if you have used any type of block theme, you have already tried this feature.

For example, you can have one color palette in theme.json, and then add a second JSON file with a different color palette. The user can then choose between the palettes in the Styles sidebar in the Site Editor.

There are four main reasons for adding theme.json variations. But the most important reason is that you bring value to the user by making it easier for them to change the look of their site without having to switch to a different theme:

  • You can provide a combination of alternative site wide (global) settings and styles
  • You can add custom block styles and section styles to quickly change colors and fonts of your patterns
  • Give users multiple color palette choices
  • Help users choose matching font pairs with font family presets

All code examples in this lesson assumes that you are using theme.json version 2 or 3. Remember that you must include the version in your .json file.

Level: ,

Estimated reading time: 7 minutes

Last updated

How global style variations work

Here is what you need to know to add style variations to your block theme:

  • Style variations use the same format as your standard theme.json file.
  • They inherit the settings and values from theme.json.
  • Anything you add to the variation overrides theme.json.

In other words, you can completely override theme.json and replace every setting. And if all you want to change is the color palette, then that is all you need to include.

When the user activates a style variation, WordPress applies the new styles in addition to the styles from theme.json. The variation overrides the default styles.

To register a style variation, color or font family preset, you need to place the JSON file inside a folder in your theme called styles, or a subfolder to styles (Props to Justin Tadlock for letting us know that subfolders work!).

Use a folder structure and names that makes it easy for you to identify the different types of variations. There is a discussion about standardizing the slugs for section styles to make it easier to switch themes, and the recommendation is to use section-1, section-2 and so on.

styles (dir)
   blue.json
   dark.json
   sections (dir)
      section-1.json
      section-2.json
   fonts (dir)
      opensans-poppins.json
      inter.json
theme.json

You can register custom block styles, section styles and color presets with PHP or JSON. This lesson focuses on JSON. You can read more about other methods in the lesson Block style variations and section styles.

Combined site wide settings and styles

You can use the first type of style variation to update both theme.json settings and styles. Including but not limited to the content width, spacing and font sizes, or the color of the link in the paragraph block.

Users with access to the Site Editor can preview and select these combined styles from the Styles sidebar > Browse Styles, or from Appearance > Editor > Styles.

If you are sharing your theme on WordPress.org, the theme directory also shows the styles
on your theme page.

Each combined style variation needs its own JSON file. By adding a title and description, you can make it easier for users to identify your style. The title is visible when a user hovers or focuses on the style option. The description is not visible in the Site Editor interface, but used for screen reader users.

{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 3,
	"title": "Maelstrom",
	"description: "Blue background and sans-serif fonts",
	...
}

For more examples please see the style variations in Twenty Twenty-Four.

Custom block styles

Custom block styles are optional styles for blocks and you select them in the block’s settings sidebar after you insert the block. One example is the option to select the rounded image:

Image block with a block style that adds rounded corners.

You have to place each custom block style in its own JSON file, or WordPress can not parse them correctly. In this file, you can only use the styles section, not settings, patterns, templates etc. This feature requires WordPress 6.6.

  • slug: The unique identifier that WordPress uses to create the CSS class.
  • blockTypes: The array of blocks that you want to apply the style to.
{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 3,
	"title": "Sub heading",
	"slug": "custom-1",
	"blockTypes": [ "core/heading" ],
	"styles": {
		"color": {
			"text": "#444"
		},
		"typography": {
			"fontFamily": "var(--wp--preset--typography--fontFamily--heading)",
			"fontSize": "var(--wp--preset--font-size--medium)",
			"textTransform": "uppercase"
		}
	}
}

WordPress applies the style to the heading block using a unique class that contains the slug “custom-x”. The unique class is required for managing nested styles, it allows using different styles for the heading block in different section styles.

:root :where(.wp-block-heading.is-style-custom-1--ca03a42443b053dd5d5803671f11c12b)

In this example I am adding the same style to multiple blocks by adding the prefix and slug to blockTypes:

{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 3,
	"title": "Post meta",
	"slug": "custom-2",
	"blockTypes": [ "core/post-author-name", "core/post-date", "core/post-terms" ],
	"styles": {
		"color": {
			"text": "#444"
		},
		"typography": {
			"fontSize": "var(--wp--preset--font-size--small)"
		}
	}
}

How to modify existing block style variations

You can use the slug of an already registered style and update the style using theme.json. Before WordPress 6.6, this only worked for styles registered by WordPress core. It now works also for third-party style variations.

Below is a basic example that updates the border radius of the rounded style for the image block:

"styles": {
	"blocks": {
		"core/image": {
			"variations": {
				"rounded" : {
					"border": {
						"radius": "8px"
					}
				}
			}
		}
	}
}

Section styles

Section styles are the same same as block styles and are a new feature in WordPress 6.6.
They are called section styles because you can now apply styles to nested blocks and elements.
A typical section may be a group block with a heading, buttons and paragraphs.

The main caveat with section styling is that it is easy to get carried away and add too many style options for group blocks and columns. Here we need to practice constraint to not overwhelm users.

All the credit for the system that I am recommending below goes to Brian Gardner, who has explored the best ways to use section styles in his theme Powder. Powder on GitHub.

Brian uses a color palette in theme.json with base, contrast, primary, and secondary. He then registers section styles for the group block, and switches the background, text color, link and button colors.

This recording is of the development version of Powder (July 2024):

Each section style is named after the color, while the slug is neutral: “section-1”, “section-2” and so on.

{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 3,
	"title": "Base",
	"slug": "section-1",
	"blockTypes": [ "core/group" ],
	"styles": {
		"color": {
			"background": "var(--wp--preset--color--base)",
			"text": "var(--wp--preset--color--contrast)"
		},
		"elements": {
			"button": {
				"color": {
					"background": "var(--wp--preset--color--primary)",
					"text": "var(--wp--preset--color--base)"
				}
			},
			"link": {
				"color": {
					"text": "var(--wp--preset--color--primary)"
				},
				":hover": {
					"color": {
						"text": "var(--wp--preset--color--contrast)"
					}
				}
			}
		}
	}
}
{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 3,
	"title": "Contrast",
	"slug": "section-2",
	"blockTypes": [ "core/group" ],
	"styles": {
		"color": {
			"background": "var(--wp--preset--color--contrast)",
			"text": "var(--wp--preset--color--base)"
		},
		"elements": {
			"button": {
				"color": {
					"background": "var(--wp--preset--color--base)",
					"text": "var(--wp--preset--color--contrast)"
				}
			},
			"link": {
				"color": {
					"text": "var(--wp--preset--color--base)"
				},
				":hover": {
					"color": {
						"text": "var(--wp--preset--color--base)"
					}
				}
			}
		}
	}
}

Brian also styles the site title and post title blocks that are nested inside the group. This is useful for the site header, footer and query loops. Like you can see in the video, it is important to maintain the color contrast if a user chooses a new color palette with a different primary color.

Complete example:

{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 3,
	"title": "Primary",
	"slug": "section-3",
	"blockTypes": [ "core/group" ],
	"styles": {
		"blocks": {
			"core/post-title": {
				"elements": {
					"link": {
						"color": {
							"text": "var(--wp--preset--color--base)"
						},
						":hover": {
							"color": {
								"text": "var(--wp--preset--color--base)"
							}
						}
					}
				}
			},
			"core/site-title": {
				"elements": {
					"link": {
						"color": {
							"text": "var(--wp--preset--color--base)"
						}
					}
				}
			}
		},
		"color": {
			"background": "var(--wp--preset--color--primary)",
			"text": "var(--wp--preset--color--base)"
		},
		"elements": {
			"button": {
				"color": {
					"background": "var(--wp--preset--color--base)",
					"text": "var(--wp--preset--color--contrast)"
				}
			},
			"link": {
				"color": {
					"text": "var(--wp--preset--color--base)"
				},
				":hover": {
					"color": {
						"text": "var(--wp--preset--color--base)"
					}
				}
			}
		}
	}
}

Known limitations

The section styles does not support blockGap (block spacing) because it was not finished in time for the release of WordPress 6.6. All improvements and iterations will be built into and tested in the Gutenberg plugin before they are added to WordPress core in future releases.

Color palette presets

Color palette presets are JSON files in the styles folder where you only change the color palette setting and nothing else. WordPress recognizes the format, and displays the variation as a palette that the user can select in the Styles sidebar in the Site Editor.

Your palette presets can use any number of colors, but the preview is limited to five colors:

The styles sidebar in the Site Editor shows two combined style variations and two palettes.
{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 3,
	"title": "Light blue",
	"description": "Two shades of light blue"
	"settings": {
		"color": {
			"palette": [
				{
					"slug": "base",
					"color": "#f0f0f0",
					"name": "Base"
				},
				{
					"slug": "contrast",
					"color": "#1e1e1e",
					"name": "Contrast"
				},
				{
					"slug": "primary",
					"color": "#00A0D2",
					"name": "Primary"
				},
				{
					"slug": "secondary",
					"color": "#0073AA",
					"name": "Secondary"
				},
				{
					"slug": "transparent",
					"color": "transparent",
					"name": "Transparent"
				}
			]
		}
	}
}

Font family presets

Font family presets work similarly to the color palette presets. You create a new JSON file where you only add the font families, and save the file in the styles folder. However there is an important limitation that you need to know about: You must first register all the fonts in theme.json, otherwise the font files will not be enqueued in the editors.

So you use theme.json to register the fonts, and then use the preset files to add font pairs that the user can preview and select in the Styles sidebar. The font family presets are displayed below the color palette presets, and also in the Typography panel:

The Typography panel in the Styles sidebar in the editor shows the current font names. There are two presets to select from at the bottom of the panel, and the second preset is activate.

Here I have copied parts of the Ember style variation in Twenty Twenty-four to a font family preset:

{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 3,
	"title": "Instrument Sans & Jost",
	"settings": {
		"typography": {
			"fontFamilies": [
				{
					"fontFace": [
						{
							"fontFamily": "Instrument Sans",
							"fontStyle": "normal",
							"fontWeight": "400 700",
							"src": [
								"file:./assets/fonts/instrument-sans/InstrumentSans-VariableFont_wdth,wght.woff2"
							]
						},
						{
							"fontFamily": "Instrument Sans",
							"fontStyle": "italic",
							"fontWeight": "400 700",
							"src": [
								"file:./assets/fonts/instrument-sans/InstrumentSans-Italic-VariableFont_wdth,wght.woff2"
							]
						}
					],
					"fontFamily": "\"Instrument Sans\", sans-serif",
					"name": "Instrument Sans",
					"slug": "body"
				},
				{
					"fontFace": [
						{
							"fontFamily": "Jost",
							"fontStyle": "normal",
							"fontWeight": "100 900",
							"src": ["file:./assets/fonts/jost/Jost-VariableFont_wght.woff2"]
						},
						{
							"fontFamily": "Jost",
							"fontStyle": "italic",
							"fontWeight": "100 900",
							"src": [
								"file:./assets/fonts/jost/Jost-Italic-VariableFont_wght.woff2"
							]
						}
					],
					"fontFamily": "\"Jost\", sans-serif",
					"name": "Jost",
					"slug": "heading"
				},
				{
					"fontFamily": "-apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif",
					"name": "System Sans-serif",
					"slug": "system-sans-serif"
				},
				{
					"fontFamily": "Iowan Old Style, Apple Garamond, Baskerville, Times New Roman, Droid Serif, Times, Source Serif Pro, serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol",
					"name": "System Serif",
					"slug": "system-serif"
				}
			]
		}
	}
}

Resources

Section Styles (The introduction post and developer note for 6.6)

Styling sections, nested elements, and more with Block Style Variations in WordPress 6.6