Theme.json typography options

In this lesson, you will learn how to use all the theme.json typography options, including:

  • Font families and font sizes
  • Enable or disable options, custom font size, and line height
  • Add default font weights, text decoration, and text transformations to blocks

In the first part, I will write about the settings and how to create presets. In the second part, I will give you examples of how to apply the typography options to the blocks. And lastly, I have included links to GitHub issues about upcoming changes.

Level: Beginner, developer

Prerequisites: Global Styles & theme.json

Estimated reading time: 13 minutes

Updated August 30, Gutenberg version 11.3.

Font family

Which blocks support font family?

You can add a default font family to any block using the theme.json styles section.
The following blocks have a font family control in the editor:
Button, list, navigation, post title, query title, site tagline, site title, verse.

The block editor Typography panel 
has a font family option with a select list with font family names.

How to add font families to the block editor

You add font families in theme.json by listing them inside the typography section under the main settings section:

settings.typography.fontFamilies

Typography options that are on the root level of the settings section create presets that can be used for the website and for all blocks.

Note that the category name for the list is fontFamilies (plural).
Inside this category, you place the font family names in an array, using the following values:

  • fontFamily: The font family names (the CSS value).
  • slug: The unique identifier, that WordPress uses in the CSS custom property.
  • name: The visible name in the editor (optional).

fontFamily can include one font or several, including your fallback font:

{
	"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": "Helvetica Neue, Helvetica, Arial, sans-serif",
					"slug": "helvetica-arial",
					"name": "Helvetica or Arial"
				}
			]
		}
	}
}

And the resulting CSS custom properties have the following format:

--wp--preset--font-family--slug: fontFamily value
body {
    --wp--preset--font-family--system-fonts: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
    --wp--preset--font-family--helvetica-arial: Helvetica Neue, Helvetica, Arial, sans-serif;
}

How to add a font family for a specific block

You can use different font families for different blocks. A common use case is to offer one set of fonts for the body paragraphs, and one for headings or the site title.

You add typography options for individual blocks under settings.blocks.blockname:

settings.blocks.blockname.typography.fontFamilies

Example:

{
	"version": 1,
	"settings": {
		"blocks": {
			"core/site-title": {
				"typography": {
					"fontFamilies": [
						{
							"fontFamily": "Helvetica Neue, Helvetica, Arial, sans-serif",
							"slug": "helvetica-arial",
							"name": "Helvetica or Arial"
						}
					]
				}
			}
		}
	}
}

The custom CSS property then uses the block selector (.wp-block-site-title) instead of body:

.wp-block-site-title {
    --wp--preset--font-family--helvetica-arial: Helvetica Neue, Helvetica, Arial, sans-serif;
}

Remember that the font will only be added to the typography panel if the block supports it.

How to use Google Fonts in the site editor

You can use a remote font provider if you like. Most importantly, the theme needs to load the font files on the front and in all three editors.
For the front, enqueue the font stylesheet with wp_enqueue_scripts.

There are two caveats: First, if you have tried using custom fonts with the site editor, you may have found that the fonts did not load correctly. The template editor and site editor iframes do not work with enqueue_block_editor_assets, which is the most common way to load fonts in the block editor.

Instead, you add the Google Fonts to the site editor with add_editor_style.
Basic example:

add_editor_style(
	array(
		'./assets/css/style-shared.min.css',
		'https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible:ital,wght@0,400;0,700;1,400;1,700&display=swap'
	)
);

add_editor_style is usually hooked into after_setup_theme.

Secondly, the theme always loads the font files, whether the current page uses the font or not. So for performance and loading speed reasons, carefully consider using system fonts or only a few custom fonts.

I recommend the Webfonts Loader script from the WordPress.org themes team. It downloads remote fonts to the wp-content/fonts folder and loads them locally instead of remotely.

Font size

Which WordPress blocks support font sizes?

Quite a few blocks have support for font size controls in the block editor:
Button, code, heading, list, navigation, paragraph, post author, post comments count, post comments form, post comments link, post comments, post date, post excerpt, post terms, post title, preformatted, query pagination next, query pagination previous, query title, site tagline, site title, term description, verse.

Default font sizes

Similar to how I described the default color palette in the previous lesson, WordPress adds the default font sizes with CSS custom properties:

--wp--preset--font-size--small: 13px;
--wp--preset--font-size--normal: 16px;
--wp--preset--font-size--medium: 20px;
--wp--preset--font-size--large: 36px;
--wp--preset--font-size--huge: 42px;

As with the colors, you can not remove the default font size CSS properties, but you can assign new values to them.

How to add new font sizes using theme.json

Font size settings for the website and all blocks are added to theme.json under settings.typography.fontSizes.

The key and value pairs used in fontSizes are:

  • size: A valid CSS font size value
  • slug: The unique identifier, that WordPress uses in the CSS custom property.
  • name: The visible name in the editor (optional).

How to add new font size values to existing font options, and why

The reason why one would go to the extent of reusing the default font size slugs is to make switching themes easier. -It helps match old content with the new style when a user switches to your theme.

The default font size "small" has the value 13px and the CSS custom property is
--wp--preset--font-size--small. You can change the value of "small" by registering a new size using the same slug.

-One of the best things you can do for the responsiveness and accessibility of your theme, is to replace the pixel value. In the example below, I am using rem, but you can use any valid CSS font size –just avoid pixels. 😉

{
	"version": 1,
	"settings": {
		"typography": {
			"fontSizes": [
				{
					"slug": "small",
					"size": "1rem",
					"name": "Small"
				},
			]
		}
	}
}

Adding a font size option for a specific block

Place your font size array inside settings.blocks.blockname.typography.fontSizes to make the size available for a specific block. This way, you can limit which font sizes that are selectable for that block.

I do not recommend limiting the font size option for the heading block or site title, because there is no way to make a font size selectable depending on the heading level. H6 and H1 would have the same font size options.

{
	"version": 1,
	"settings": {
		"blocks": {
			"core/button": {
				"typography": {
					"fontSizes": [
						{
							"slug": "normal",
							"size": "1.25rem",
							"name": "Normal"
						},
						{
							"slug": "medium",
							"size": "1.5rem",
							"name": "medium"
						}
					]
				}
			}
		}
	}
}

The CSS output for the above example uses the class for the text inside the button block,
wp-block-button__link:

.wp-block-button__link {
    --wp--preset--font-size--normal: 1.25rem;
    --wp--preset--font-size--medium: 1.5rem;
}

How to disable the custom font size option

The custom font size option is the input field where users can enter a font size and unit manually:

The custom font size option in the Typography panel has a number input field and list of selectable units: px, em, rem.

The option is enabled by default. To disable it, set typography.customFontSize to false:

{
	"version": 1,
	"settings": {
		"typography": {
			"customFontSize": false
		}
	}
}

You can also disable it for specific blocks:

{
	"version": 1,
	"settings": {
		"blocks": {
			"core/paragraph": {
				"typography": {
					"customFontSize": false
				}
			}
		}
	}
}

How to disable the font size option

Leave the array inside settings.typography.fontSizes empty to disable the font size option:

{
	"version": 1,
	"settings": {
		"typography": {
			"fontSizes": []
		}
	}
}

Here is an example of how you can add font sizes, but disable the control for a specific block:

{
	"version": 1,
	"settings": {
		"typography": {
			"fontSizes": [
				{
					"slug": "small",
					"size": "1rem",
					"name": "Small"
				},
				{
					"slug": "normal",
					"size": "1.25rem",
					"name": "Normal"
				},
				{
					"slug": "medium",
					"size": "1.5rem",
					"name": "medium"
				}
			]
		},
		"blocks": {
			"core/list": {
				"typography": {
					"fontSizes": []
				}
			}
		}
	}
}

Line height

The custom line height setting is one of the controls that are not experimental. It is supported in WordPress core without the Gutenberg plugin. This setting is the equivalent of add_theme_support( 'custom-line-height' );. Custom line height is disabled by default.

The following blocks support the custom line height control:
Heading, navigation, paragraph, post author, post comments count, post comments form, post comments link, post comments, post date, post excerpt, post terms, post title, query pagination next, query pagination previous, query title, site tagline, site title, term description.

In comparison to the font family and font size it is not possible to assign selectable values to the line height control.

You can enable the line height control for the above blocks by setting typography.customLineHeight to true:

{
	"version": 1,
	"settings": {
		"typography": {
			"customLineHeight": true
		}
	}
}

Use the following example to add support for line height to a single block:

{
	"version": 1,
	"settings": {
		"blocks": {
			"core/site-tagline": {
				"typography": {
					"customLineHeight": true
				}
			}
		}
	}
}

Or enable it on the root level and disable it for a specific block:

{
	"version": 1,
	"settings": {
		"typography": {
			"customLineHeight": true
		},
		"blocks": {
			"core/site-tagline": {
				"typography": {
					"customLineHeight": false
				}
			}
		}
	}
}

Drop Cap

The drop cap is a text setting that is only enabled for the paragraph block.
To disable the drop cap, set the value of settings.typography.dropCap to false:

{
	"version": 1,
	"settings": {
		"typography": {
			"dropCap": false
		}
	}
}

The drop cap is different from the other typography features because it is a
block attribute, not a block support.

There is no way to set the position or size of the drop cap using theme.json.
To style the drop cap, use the .has-drop-cap:not(:focus):first-letter CSS selector in your theme CSS.

Font weight

The following blocks support the font weight control: Heading, navigation, and site title.
Font weight is enabled in the block editor by default, and you can select between these values:

  • Thin: 100
  • Extra Light: 200
  • Light: 300
  • Regular: 400
  • Medium: 500
  • Semi Bold: 600
  • Bold: 700
  • Extra Bold: 800
  • Black: 900

You can disable the font weight control for all blocks with the following code in theme.json:

{
	"version": 1,
	"settings": {
		"typography": {
			"customFontWeight": false
		}
	}
}

And for a single block:

{
	"version": 1,
	"settings": {
		"blocks": {
			"core/site-title": {
				"typography": {
					"customFontWeight": false
				}
			}
		}
	}
}

Font style

The font style control is supported by the navigation and site title blocks and has three options: default, regular and italic:

The custom font style option has a select list with three options: Default, Regular, and italic.

You can turn off the font style for all bocks by setting typography.customFontStyle to false in theme.json:

{
	"version": 1,
	"settings": {
		"typography": {
			"customFontStyle": false
		}
	}
}

How to turn off font style for a single block:

{
	"version": 1,
	"settings": {
		"blocks": {
			"core/site-title": {
				"typography": {
					"customFontStyle": false
				}
			}
		}
	}
}

Text transform

The text transform control inside the typography panel includes the option to change the text to uppercase, lower case, or capitalized:

The letter case block setting controls uses three buttons with icons representing upper case, lower case and capitalized.

The block editor only supports the text transform control for the navigation, site tagline, and site title blocks.
It is enabled by default, and you disable it by setting typography.CustomtextTransform to false:

{
	"version": 1,
	"settings": {
		"typography": {
			"customTextTransforms": false
		}
	}
}

Example of how you can disable it for a single block:

{
	"version": 1,
	"settings": {
		"blocks": {
			"core/site-tagline": {
				"typography": {
					"customTextTransforms": false
				}
			}
		}
	}
}

Text decoration

You can use the text decoration control in the block editor to add an underline or a line through the link text.

The text decoration option has two buttons with icons representing underlined text and text with a lin through it.

Example home navigation block items with two different decorations:

If you want to disable the text decoration option, set typography.customTextDecorations to false:

 {
	"version": 1,
	"settings": {
		"typography": {
		      "customTextDecorations": false
		}
	}
}

Applying typography styles with theme.json

These code examples assume that your theme has all typography settings enabled.

You can add typography styles for the website and as defaults for all blocks in the root level of the styles section in theme.json:

{
	"version": 1,
	"styles": {
		"typography": {
			"fontFamily": "value",
			"fontSize": "value",
			"fontStyle": "value",
			"fontWeight": "value",
			"lineHeight": "value",
			"textDecoration": "value",
			"textTransform": "value"
		}
	}
}

You can use any valid CSS. In this example, I have used presets for the system fonts for the body, and medium text size (defaults to 20px).

{
	"version": 1,
	"styles": {
		"typography": {
			"fontFamily": "var(--wp--preset--font-family--system-fonts)",
			"fontSize": "var(--wp--preset--font-size--medium)"
		}
	}
}

CSS output:

body {
    font-family: var(--wp--preset--font-family--system-fonts);
    font-size: var(--wp--preset--font-size--medium);
}

-Setting a default font weight or line height for the body element would have limited effect because the block styles would have a higher specificity (assuming that you are using the default block styles provided by Gutenberg and WordPress).

If you want to override browser styles and block styles for headings and paragraphs, target those blocks instead.

Expand to view an example structure with elements (links and headings)

I included the H1 heading in the example. To add support for more headings, repeat the styles for level H2 to H6.

{
	"version": 1,
	"styles": {
		"typography": {
			"fontFamily": "value",
			"fontSize": "value",
			"fontStyle": "value",
			"fontWeight": "value",
			"lineHeight": "value",
			"textDecoration": "value",
			"textTransform": "value"
		},
		"elements": {
			"link": {
				"typography": {
					"fontFamily": "value",
					"fontSize": "value",
					"fontStyle": "value",
					"fontWeight": "value",
					"lineHeight": "value",
					"textDecoration": "value",
					"textTransform": "value"
				}
			},
			"h1": {
				"typography": {
					"fontFamily": "value",
					"fontSize": "value",
					"fontStyle": "value",
					"fontWeight": "value",
					"lineHeight": "value",
					"textDecoration": "value",
					"textTransform": "value"
				}
			}
		}
	}
}

You add styles for individual block types under styles.blocks.blockname.typography:

{
	"version": 1,
	"styles": {
		"blocks": {
			"core/site-tagline": {
				"typography": {
					"fontFamily": "value",
					"fontSize": "value",
					"fontStyle": "value",
					"fontWeight": "value",
					"lineHeight": "value",
					"textDecoration": "value",
					"textTransform": "value"
				}
			}
		}
	}
}
Expand to view an example structure with a single block and elements (links and headings)

I included the H1 heading in the example. To add support for more headings, repeat the styles for level H2 to H6.

{
	"version": 1,
	"styles": {
		"blocks": {
			"core/site-title": {
				"typography": {
					"fontFamily": "value",
					"fontSize": "value",
					"fontStyle": "value",
					"fontWeight": "value",
					"lineHeight": "value",
					"textDecoration": "value",
					"textTransform": "value"
				},
				"elements": {
					"link": {
						"typography": {
							"fontFamily": "value",
							"fontSize": "value",
							"fontStyle": "value",
							"fontWeight": "value",
							"lineHeight": "value",
							"textDecoration": "value",
							"textTransform": "value"
						}
					},
					"h1": {
						"typography": {
							"fontFamily": "value",
							"fontSize": "value",
							"fontStyle": "value",
							"fontWeight": "value",
							"lineHeight": "value",
							"textDecoration": "value",
							"textTransform": "value"
						}
					}
				}
			}
		}
	}
}

Upcoming changes

There are plans to place the theme.json typography options inside the new tools panel. The panel where you can toggle controls on and off. Gutenberg first introduced this panel for the padding controls in version 11.3:

An example of the tools panel used for the dimension block controls. It has a drop down menu with a list of available controls that can be displayed or hidden.

Read more about the new tools panel component: https://github.com/WordPress/gutenberg/pull/32392

ToolsPanel: Refining the component’s behaviour:
https://github.com/WordPress/gutenberg/issues/34257

The letter spacing control has been unavailable for several Gutenberg versions, and needs to be updated to work with the new panel. This is why it I did not include it in this lesson (August 29, 2021).

There are also ongoing discussions about changing which controls should be available for which blocks, and what type of options that should be visible by default.

Typography Tools Tracking issue:
https://github.com/WordPress/gutenberg/issues/34345

Typography: Switch to ToolsPanel for display UI
https://github.com/WordPress/gutenberg/pull/33744

Resources