Global Styles & theme.json

Global styles is a system created to help users change the overall style of their site without having to edit individual blocks or pages. Its purpose is also to lower the entry barrier and make it easier for theme developers to style blocks.

In this lesson, you will learn what global styles are, how to create a theme.json file, and how you can benefit from global styles.

Level: Beginner, intermediate, developer

Estimated reading time: 12 minutes

What are Global Styles?

Global styles is a system and interface created to help users change the overall style of their site without having to edit individual blocks or pages. Users can select a body background color or change the line height of all their headings from one place. Styles added to individual blocks will still override the global styles.
From a theme developer perspective, global styles make it easier to style blocks in the editor and front.

Even though it is called Global Styles, it is used for both styles and enabling or disabling settings and features. A feature can be, for example, the drop cap.

The global styles interface

The global styles interface is still experimental, but if you are using the latest version of Gutenberg and enable a full site editing theme, you can preview and test the new controls.
You find the controls inside a separate sidebar panel in the site editor.
First, access the site editor via the WordPress admin menu:

The site editor menu item is available In the WordPress admin area when a full site editing theme is active. It is located above the Appearance menu item.

Next, open the Global Styles sidebar by clicking on the Aa icon:

  • Global styles affect the website. The background color that you select here is the body background.
  • By Block Type affects all copies of a block of that type, for example, all group blocks.

The placement, naming and design of the controls may still change before they are moved from Gutenberg to WordPress core.

Global styles sidebar
Early version of the global styles interface

Who benefits from Global Styles?

Besides the users who will have more possibilities to change the look of their sites, global styles also benefit new theme developers.

The new controls will drastically reduce the need for custom solutions for styling, for example, a theme options panel or customizer settings.

-It lowers the entry barrier for new theme developers while allowing control of the styles.

How does global styles work?

Global styles work with the help of a new theme settings file called theme.json. Theme developers can use JSON to define defaults for both the website and blocks.

The data from the JSON objects are parsed and reformatted as CSS and CSS custom properties.
WordPress then loads the styles in the editors and on the front.

In earlier versions of Gutenberg, a block needed to register support for the style properties before you could control the properties with theme.json. This is no longer the case. You can now style all blocks, including third-party blocks from plugins.

View of the block.json file for a group block. The file includes the block information, attributes and block supports.
An example block that has registered support for alignments and gradients.

The block must register support for the user-facing control to be visible in the block settings sidebar. Theme.json can not add controls to blocks that do not already register support but can be used to disable controls.

For those who are interested in seeing how the data is fetched, stored and parsed, see the global-styles.php file in the Gutenberg plugin.

The way CSS is loaded was improved significantly in Gutenberg version 9.6. Gutenberg now only loads the styles of the blocks that are used on a page.
If you are interested in learning about the continued work to improve the performance, see https://github.com/WordPress/gutenberg/pull/28358

The theme.json file

A file called theme.json is created and placed inside the main folder of the theme.
If you have already taken the block attributes lesson, you may recognize the format.

A view of the theme.json file from Armando. The code is truncated but displays the settings section with color, typography, spacing and layout settings.

New to JSON and want to read more about it? Then I recommend these resources:
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/JSON
https://www.json.org/json-en.html

You start the file with two curly brackets, { } and all the content will be placed inside these brackets.

Then use a format with property names and values, encased in double quotes and separated with a colon:

{
"property-name": "value"
}

The property name can be a block name or a setting:

"core/heading": {
	"typography": {
		...
	}
}

You will see how these can be nested in several levels in the examples below.

Versioning

You need to include the version at the top of your file inside the first set of curly brackets.
Version 1 of the theme.json format is considered stable.

{
	"version": 1
}

Main sections

You separate the theme.json file into two main sections: settings and styles.

-There are also sections for other types of information like post templates and template parts, these are described under additional sections.

  • Settings:
    • The editor configuration. Enables or disables features like custom font sizes, custom padding, and colors.
    • Defines preset values such as color palettes that generates CSS custom properties that you can use in the theme. You can define presets for both the website and per block type.
  • Styles:
    Applies styling to the website or the blocks, with or without the generated CSS custom properties.
{
        "version": 1,
	"settings": {
		"blocks": {
		}
	},
	"styles": {
                "blocks": {
                }
	}
}

Settings presets

Presets are defaults for controls and custom CSS properties. They are generated from the values in the settings section.
Every preset is described using a preset category. The categories are block supports, and some have subcategories.

Available categories:

  • Color
  • Typography
  • Layout
  • Spacing
  • Border
  • Custom

Color

In the example below, the preset category is color, and the subcategories of color are palette, duotone, and gradients.

In the official documentation, this nesting is sometimes presented as
settings.color.palette, settings.blocks.blockname.color.gradients

You place multiple values inside arrays and separate properties with a comma:

{
"version": 1,
"settings": {
	"color": {
		"palette": [
			{
			     "slug": "purple",
			     "color": "#D1D1E4",
			     "name": "Purple"
			},
			{
			     "slug": "red",
			     "color": "#E4D1D1",
			     "name": "Red"
			}
		],
		"gradients": [
			{
			"slug": "purple-to-red",
			"gradient": "linear-gradient(160deg, var(--wp--preset--color--purple), var(--wp--preset--color--red))",
			"name": "Purple to Red"
			}
		],
                "duotone": [
		         {
				"colors": [ "#1d1f35", "#6cace4" ],
				"slug": "dark-blue-and-light-blue",
				"name": "Dark blue and light blue"
			},
			{
				"colors": [ "#1d1f35", "#c7c0af" ],
				"slug": "dark-blue-and-beige",
				"name": "Dark blue and beige"
			}
		]
             }
      }
}

If you look at the gradient above, you can see that it uses the purple and red colors from the palette. Each preset generates a CSS custom property using this naming convention:

--wp--preset--{preset-category}--{preset-slug}

And the output from the example is:

--wp--preset--color--purple: #D1D1E4;
--wp--preset--color--red: #E4D1D1;

--wp--preset--gradient--purple-to-red: linear-gradient(160deg, var(--wp--preset--color--purple), var(--wp--preset--color--red));

Typography

You can add font families and font sizes under the typography category.

FontFamilies contains an array with the following keys:

  • fontFamily: A font family set with a list of one or more font family names.
  • slug: The slug used to identify the font family set, also used in the CSS custom property.
  • name: The visible name of the font family set in the editor. Optional.

FontSizes is the theme.json equivalent of add_theme_support( "editor-font-sizes" ).
The size property can use any valid CSS font size.

{
	"version": 1,
	"settings": {
		"typography": {
			"fontFamilies": [
				{
					"fontFamily": "-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif",
					"slug": "system-fonts",
					"name": "System Fonts"
				},
				{
					"fontFamily": "Geneva, Tahoma, Verdana, sans-serif",
					"slug": "geneva-verdana"
				}
			],
			"fontSizes": [
				{
					"slug": "small",
					"size": "1rem",
					"name": "Small"
				},
				{
					"slug": "extra-large",
					"size": "3rem",
					"name": "Extra large"
				}
			]
		}
	}
}

August 6, 2021
Heads up: There is a known bug with font families when WordPress 5.8 and Gutenberg is used. The font family CSS is missing on the front of the website. The bug has been found and will be fixed in Gutenberg 11.3.

Layout and content width

The layout category replaces add_theme_support( 'align-wide' ); and defines the width of the content.

  • contentSize -Default block width.
  • wideSize -Width of blocks with the wide align setting enabled.

This setting does not output CSS custom properties.

Place this code under settings:

"layout": {
	"contentSize": "840px",
	"wideSize": "1100px"
}

Custom presets

When you use custom presets, you are not limited to using properties that the block supports.
In comparison to standard presets, they do not influence the block controls in the editor.

A custom preset can be anything. If you want to handle all your CSS custom properties in one settings file, you can use theme.json to create custom CSS custom properties that you can use anywhere in your CSS.

"custom": {
	"spacing": "14px"
}

Custom preset generates a CSS custom property using this naming convention:

--wp--custom--slug

Because of this, you should not use -- in your slug or values.

The output from the example is:

--wp--custom--spacing: 14px;

Presets for blocks

I mentioned that you could define presets for both the website and blocks. With block presets, you can enable a feature across the site and disable it for specific block types, or the other way around.

You can create a color palette specifically for a block in the same way you create a default color palette. The block editor then displays the block palette instead of the default palette.

These code examples are truncated but illustrate how you can create block presets.
Create a new section called blocks inside settings:

{
    "version": 1,
    "settings": {
           "blocks": {
           }
    }
}

Add the name of the block inside the new blocks section. In this example, I am using the heading block:

{
    "version": 1,
    "settings": {
           "blocks": {
              "core/heading":{
              }
           }
    }
}

Any presets that you create inside this section will only apply to the heading block.

"core/heading":{
       "color": {
		"palette": [
			{
				"slug": "dark-blue",
				"color": "#1d1f35",
				"name": "Dark blue"
			}
		]
       }
}
Example with both color palettes together.
{
	"version": 1,
	"settings": {
		"color": {
			"palette": [
				{
					"slug": "black",
					"color": "#000",
					"name": "Black"
				},
				{
					"slug": "white",
					"color": "#fff",
					"name": "White"
				}
			]
		},
		"blocks": {
			"core/heading": {
				"color": {
					"palette": [
					        {
						        "slug": "dark-blue",
							"color": "#1d1f35",
							"name": "Dark blue"
						},
						{
							"slug": "light-blue",
							"color": "#6cace4",
							"name": "Light blue"
						}
					]
				}
			}
		}
	}
}
	

Enable or disable features

Reminder: When a feature is enabled, the editor control is available, but only for the blocks that have registered support.

Typography features

  • customFontSize: Let the user select a custom size value. Enabled by default, set to false to disable.
  • dropCap: Let the user add a drop cap. Enabled by default, set to false to disable.
  • customFontWeight: Enabled by default, set to false to disable.
  • customLineheight: Opt-in, set to true to enable.
  • customFontStyle: Enabled by default, set to false to disable.

Example code:

"typography": {
	"customLineHeight": true,
        "customFontSize": false,
        "dropCap": false
}

Color

  • custom: Let the user select custom colors using the color picker. Enabled by default, set to false to disable.
  • customGradient: Let the user select custom gradients using the color picker. Enabled by default, set to false to disable.
  • link: Let the user select link text color. Used for all link states. Opt-in, set to true to enable.
"color": {
	"custom": false,
	"customGradient": false,
        "link": true
}

Padding & Margin

Enable support for custom padding and margin:

"spacing": {
        "customPadding": true,
	"customMargin": true
}

Enable custom units for the margin and padding:

"spacing": {
	"customPadding": true,
	"customMargin": true,
        "units": [ "px", "em", "rem", "vh", "vw" ]
}

Border

Enable support for borders:

"border": {
	"customColor": true,
	"customRadius": true,
	"customStyle": true,
	"customWidth": true
}

Styles

Objects at the top level of the styles section are styles that affect the website.
Objects inside “blocks” are styles that affect the named block.

In the example, I use a color hex value for the background and a global styles preset for the text. I have defined the preset in the settings but truncated it for readability.

{
        "version": 1,
	"settings": { ... },
	"styles": {
		"color": {
			"background": "#FFF",
			"text": "var(--wp--preset--color--purple)"
		}
	}
}

And the CSS output is:

body {
	background-color: #FFF;
	color: var(--wp--preset--color--purple);
}

Block Styles

Block styles are default styles for blocks. The styles are applied to all instances of a block.

  • Block styles override global styles.
  • You can override the styles per block by selecting the block in the editor and adjusting the options.
  • The theme can add additional styles to override the individual block styles.

For block styles, the category name is always an existing property.

The available properties can be found in the official documentation and in the block reference.

In the example, the red text color is applied to the heading block:

{
        "version": 1,
	"settings": {...},
	"styles": {
		...,
               "blocks": {
	             "core/heading": {
			     "color": {
				      "text": "var(--wp--preset--color--red)"
			     }
		     }
              }
	}
}

The resulting CSS output is:

h2 { color: var(--wp--preset--color--red); }

Additional sections

Template part areas

With full site editing, there are two optional template part areas: header and footer. More template part areas are likely to be added later.

A template part that has been designed as a header can be assigned to the header area.
This helps users select the correct templates when they are creating or editing their website.

This section is at the base level of theme.json. The section name is templateParts, followed by the name and slug of the template part and the name of the area.

In the example, the template part file name is header.html, which means that header is the slug you need to use as a value for the name property:

"templateParts": [
	{
		"name": "header",
		"area": "header"
	}
]

wp_template_part_area is a taxonomy for the wp_template_part post type.

Custom templates

A custom template is a template that you can select in the site editor or block editor in the Template section.

With a traditional PHP-based theme, you place the required information in the file header of the template file:

/**
 * Template Name: Grid
 *
 * Description: A Page Template that displays your posts in a grid.
 *
 * @package Aaron
 */

With full site editing, you list templates in theme.json.
The section name is customTemplates, and just like the settings, styles and templateParts, the section is at the base level of theme.json.

The first key is the name and slug of the template. In the example, I have named the template file page-home.html, and the slug is page-home.

  • title is the template name that is visible in the editor.
  • postTypes is an array of supported post types. The default is page.
"customTemplates": [
	{
		"name": "page-home",
		"title": "Page without title",
		"postTypes": [ "page", "post" ]
	}
]