In this lesson, you will learn about basic usage of the theme.json layout and spacing options, including content width, spacing and spacing units, and blockGap.
This lesson has been updated in preparation for WordPress version 6.3.
Prerequisites: Global Styles & theme.json.
Estimated reading time: 11 minutes
Last updated
The layout setting
The theme.json layout
setting decides the width of the content and enables wide and full width blocks. This setting replaces add_theme_support( 'align-wide' );
.
If you do not enable the layout setting in theme.json, the blocks are full width and aligned to the left in the block editor.
How to set content width using theme.json
The layout setting uses two key and value pairs:
contentSize sets the default width of the blocks in the editor and front.
wideSize enables the wide width option and sets the width for wide blocks.
- You can use
contentSize
alone to allow full width but not wide width. - There is no theme.json setting for specifying a more precise width for the full width option.
If you include a value for the wideSize
but not the contentSize
, the editor will show the align none and align wide options, but the actual width of the block is the value placed in the wideSize
setting.
Theme.json code example:
{
"version": 2,
"settings": {
"layout": {
"contentSize": "840px",
"wideSize": "1100px"
}
}
}
Pixels are only one example; you can use any valid CSS width.
It is not possible to have different default content widths for different blocks or to disable wide and full widths for some blocks.
The setting uses a max-width
combined with auto margins:
Default (called “None” in the editor):
.wp-container-id > * {
max-width: 840px;
margin-left: auto !important;
margin-right: auto !important;
}
Wide:
.wp-container-id > .alignwide {
max-width: 1100px;
}
Full:
.wp-container-id .alignfull {
max-width: none;
}
The block editor layout controls
When you add the layout setting to theme.json, you enable the additional layout controls in the editor.
The following blocks use the inner block width control: Query loop, group, post content, cover, media & text, and column. However, different blocks also start with different default values.
A group block placed in the Site Editor will have the setting “Inner blocks use content width” enabled:
While the post content block disables the setting:
When Inner blocks use content width is toggled on:
- The default width of the inner blocks is the value that your theme has assigned as the contentWidth in theme.json.
- You can specify the width of the inner blocks using the input fields in the layout panel.
- You can justify the blocks to the left, center, or right.
When Inner blocks use content width is toggled off:
- The content width options in the layout panel are unavailable.
- The inner blocks are always justified to the left (on ltr) and fill the width of the parent block.
Several other blocks support the justification controls in the layout panel, for example, the navigation and pagination blocks:
Can I disable the layout width settings?
In WordPress 6.3, there is no way to completely disable these settings using theme.json.
- ContentSize and wideSize can no longer be set to null or false, instead, it requires a string.
- With the settings.layout removed from theme.json, the post content block shows an empty layout panel, while the group block still has the following layout settings:
Custom units
The default units for the width, height, and spacing controls vary depending on the block.
The navigation block and the social link blocks specify their units in the block.json file.
Other blocks get their default units from the UnitControl component.
The selectable units are px, em, rem, %, vw, and vh. You can add or remove units using settings.spacing.units
:
{
"version": 2,
"settings": {
"spacing": {
"units": [ "px","em","rem"]
}
}
}
The setting replaces add_theme_support( 'custom-units', array() );
.
If you only include one unit, the unit does not show in the control.
Margin and padding
How to enable margin and padding in theme.json
Margin and padding settings are disabled (false
) by default. If you have enabled appearanceTools
in the settings
section of theme.json, you do not need to enable margin and padding separately.
You can enable margin and padding for all supported blocks under settings.spacing
in theme.json:
{
"version": 2,
"settings": {
"spacing": {
"margin": true,
"padding": true
}
}
}
How to enable or disable padding and margin for individual block types:
{
"version": 2,
"settings": {
"blocks": {
"core/group": {
"spacing": {
"padding": false
}
},
"core/site-title": {
"spacing": {
"padding": true,
"margin": false
}
}
}
}
}
Which blocks support margins?
Spacing support improved greatly in WordPress 6.1 compared to earlier versions.
Please see the updated list in the block reference.
Which blocks support padding?
Please see the updated list in the block reference.
The dimensions panel
Some blocks display one or both spacing options by default. For other blocks, you need to toggle the option using the + or ellipsis button:
How to add default margin and padding to the <body> element
You can add a default margin and padding to the <body>
element in the styles
section of theme.json. using styles.spacing.margin
and styles.spacing.padding
:
{
"version": 2,
"settings": {
"spacing": {
"margin": true,
"padding": true
}
},
"styles": {
"spacing": {
"margin": {
"top": "0px",
"right": "0px",
"bottom": "60px",
"left": "0px"
},
"padding": {
"top": "100px",
"right": "0px",
"bottom": "0px",
"left": "0px"
}
}
}
}
CSS output:
body {
margin-top: 0px;
margin-right: 0px;
margin-bottom: 60px;
margin-left: 0px;
padding-top: 100px;
padding-right: 0px;
padding-bottom: 0px;
padding-left: 0px;
}
How to add default margin and padding to blocks
You can apply a default margin or padding to a block under styles.blocks
in theme.json:
styles.blocks.blockname.spacing.margin
styles.blocks.blockname.spacing.padding
Examples:
{
"version": 2,
"settings": {
"spacing": {
"margin": true,
"padding": true
}
},
"styles": {
"blocks": {
"core/button": {
"spacing": {
"padding": {
"top": "0.3rem",
"right": "1rem",
"bottom": "0.3rem",
"left": "1rem"
}
}
},
"core/social-links": {
"spacing": {
"margin": {
"top": "0px",
"bottom": "0px"
}
}
},
"core/latest-comments": {
"spacing": {
"padding": {
"left": "0px"
}
}
}
}
}
}
You can also add spacing to elements
inside a block:
{
"version": 2,
"settings": {
"spacing": {
"margin": true,
"padding": true
}
},
"styles": {
"blocks": {
"core/post-excerpt": {
"elements": {
"link": {
"spacing": {
"padding": {
"top": "0.3rem",
"bottom": "0.3rem"
}
}
}
}
}
}
}
}
BlockGap
What is blockGap?
The blockGap
setting in theme.json sets the vertical spacing between blocks by adjusting the margins depending on the position of the block:
- The first block on the webpage and the first inner block or child block have no top or bottom margin.
- The following blocks have a top margin corresponding to the value in the theme.json setting, and no bottom margin.
The block editor also uses blockGap for horizontal spacing between columns, gallery items, buttons, and social icons.
The default value for the CSS preset (--wp--style--block-gap
) vary depending on the block, usually 2em for margins and 0.5em for gap
.
The control for blockGap in the editor is called Block spacing, and you can find it in the dimensions panel:
How to enable blockGap
The blockGap settings are disabled (false
) by default, meaning if you don’t want to use blockGap, you don’t need to do anything.
-If you have enabled appearanceTools
in the settings
section of theme.json, you do not need to enable blockGap separately.
{
"version": 2,
"settings": {
"spacing": {
"blockGap": true
}
}
}
How to add a default blockGap value
You can set a site-wide or block-specific value for blockGap inside the styles
section in theme.json:
{
"version": 2,
"settings": {
"spacing": {
"blockGap": true
}
},
"styles": {
"spacing": {
"blockGap": "1.5rem"
}
}
}
Can I add a blockGap value to a single block type?
Example:
{
"version": 2,
"settings": {
"spacing": {
"blockGap": true
}
},
"styles": {
"blocks": {
"core/group": {
"spacing": {
"blockGap": "1.5rem"
}
}
}
}
}
Spacing presets
With spacing presets, both developers and users can select from predefined values for padding, margin and block spacing (block gap). The purpose is to make it easier to use consistent spacing throughout the website.
Presets are automatically enabled once you enable spacing in theme.json. If you have enabled any spacing setting like margin or padding, the spacing presets are also enabled.
The block editor displays the presets as a stepped slider:
Spacing presets can be used with or without a scale. The default is to use a scale, but you can choose to disable the scale and use custom values.
How to use the default spacing scale
There are seven steps in the default scale (in addition to the first step, 0), and each step multiplies the value by 1.5. Each value is assigned to a CSS custom property:
CSS custom property | Value | Editor label |
---|---|---|
–wp–preset–spacing–20 | 0.44rem | 2X-Small |
–wp–preset–spacing–30 | 0.67rem | X-Small |
–wp–preset–spacing–40 | 1rem | Small |
–wp–preset–spacing–50 | 1.5rem | Medium |
–wp–preset–spacing–60 | 2.25rem | Large |
–wp–preset–spacing–70 | 3.38rem | X-Large |
–wp–preset–spacing–80 | 5.06rem | 2X-Large |
In this theme.json example I have used the preset to add margin to the post title:
{
"version": 2,
"settings": {
"spacing": {
"margin": true,
"padding": true
}
},
"styles": {
"blocks": {
"core/post-title": {
"spacing": {
"margin": {
"bottom": "var(--wp--preset--spacing--50)",
"top": "var(--wp--preset--spacing--30)"
}
}
}
}
}
}
Inside HTML templates, it is recommended to add spacing presets to the block comment using pipe symbols:
<!-- wp:post-title {"style":{"spacing":{"padding":{"top":"var:preset|spacing|30","right":"var:preset|spacing|30","bottom":"var:preset|spacing|30","left":"var:preset|spacing|30"}}}} /-->
Note that the pipe symbol should not be used inside the block’s style
attribute. Below is an example of a group block with padding on all sides:
<!-- wp:group {"layout":{"type":"constrained"},"style":{"spacing":{"padding":{"top":"var:preset|spacing|30","right":"var:preset|spacing|30","bottom":"var:preset|spacing|30","left":"var:preset|spacing|30"}}}} -->
<div class="wp-block-group" style="padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--30)"></div>
<!-- /wp:group -->
How to add your own custom spacing scale
You create your custom spacing scale under settings.spacing.spacingScale in theme.json.
The properties are:
- operator: Use
+
to increase or*
to multiply. The default is to multiply. - increment: A number. Each step in the scale is increased or multiplied with this value. The default value is 1.5.
- steps: The number of steps to use in the scale. The default is 7.
- mediumStep: A number. The medium value in the scale. The default value is 1.5.
- unit: A string of valid CSS spacing units. The available values are: px, em, rem (default), vh, vw and %.
This example snippet autogenerates a scale based on the medium step.
This code is all you need if you want custom values, but you don’t feel a need to change the slugs or names (the visible name in the editor):
{
"version": 2,
"settings": {
"spacing": {
"margin": true,
"padding": true,
"spacingScale": {
"operator": "*",
"increment": 1.5,
"steps": 7,
"mediumStep": 1.5,
"unit": "rem"
}
}
}
}
Keeping the default slugs and names makes your code more portable, and that way, you can easily modify the spacingScale in your theme’s style variations.
Using spacing preset values without a scale
There are several use cases for using presets without a scale. Perhaps the most common reason is to have values that scale, but needing to skip one or two steps and add a custom value.
To add custom sizes, you will use the spacingSizes
setting with the attributes size
, slug
and name
. The size can be any valid CSS size value, including clamp.
- SpacingSizes replaces the default options in the spacing controls in the editor.
- If you want to use the default presets but add a custom size to the scale, you must add all sizes to your theme.json since the theme.json setting overrides the default sizes.
- The default CSS custom properties are still output for compatibility reasons, but are not visible in the control.
- It is strongly recommended to use numeric slugs that range from the smallest to the largest size.
This example is copied from the theme Twenty Twenty-Three. This example is truncated, but notably, the smallest size, with the slug 20, is not being used:
"spacing": {
"spacingSizes": [
{
"size": "clamp(1.5rem, 5vw, 2rem)",
"slug": "30",
"name": "1"
},
{
"size": "clamp(1.8rem, 1.8rem + ((1vw - 0.48rem) * 2.885), 3rem)",
"slug": "40",
"name": "2"
},
{
"size": "clamp(2.5rem, 8vw, 6.5rem)",
"slug": "50",
"name": "3"
},
]
}
The order in which you place the sizes is crucial. The control in the editor will display the sizes in the order you have added them in theme.json.
Do not do the following because “Hello” will show in between size one and two, even though it’s size value is larger. This would make the spacing controls more difficult to use:
"spacingSizes": [
{
"size": "1rem",
"slug": "10",
"name": "1"
},
{
"size": "6rem",
"slug": "hello",
"name": "Hello"
},
{
"size": "2rem",
"slug": "20",
"name": "2"
}
],
Can I use different spacing presets for different blocks?
At this time, it is not possible to have different spacing presets for different block types.
How to disable custom spacing
By default, users can enter their own custom values and units in the spacing control:
You can disable this ability by setting customSpacingSize
to false:
{
"version": 2,
"settings": {
"spacing": {
"customSpacingSize": false
}
}
}
If you want to disable the default spacing scale, you can set the spacingScale steps to 0 using the following example:
{
"version": 2,
"settings": {
"spacing": {
"spacingScale": {
"steps": 0
}
}
}
}
Padding aware alignments
Since the introduction of full width blocks, theme developers have tried different ways to adjust the width of the content that is placed inside full width container blocks.
- For example, when you used a full width group or columns block with paragraphs inside, the text would touch the edge of the browser window. -Unless you added padding or a background to each block.
- Secondly, if we added a padding to the root level in the theme.json styles section (styles.spacing.padding), it meant that the blocks were no longer full width.
Gutenberg version 13.8 adds a new theme.json setting called useRootPaddingAwareAlignments that aims to solve this. The setting is opt-in. Enabling it adds four new CSS variables:-wp--style--root--padding-top/right/bottom/left
,
which uses the value from styles.spacing.padding
:
{
"version": 2,
"settings": {
"appearanceTools": true,
"useRootPaddingAwareAlignments": true,
"layout": {
"contentSize": "840px",
"wideSize": "1100px"
}
},
"styles": {
"spacing": {
"padding": {
"top": "1rem",
"right": "1rem",
"bottom": "1rem",
"left": "1rem"
}
}
}
}
You must use separate values for the padding; using a single value does not work.
If the value in settings.styles.spacing.padding is 1rem, WordPress adds 1rem padding to the body:
body {
--wp--style--root--padding-top: 1rem;
--wp--style--root--padding-right: 1rem;
--wp--style--root--padding-bottom: 1rem;
--wp--style--root--padding-left: 1rem;
}
Next, the setting adds a CSS class called .has-global-padding
and calculates wether full width blocks should have a negative left or right margin. This margin compensates for the added padding.
<div class="has-global-padding is-layout-flow wp-container-2 wp-block-group alignfull">
.has-global-padding > .alignfull {
margin-right: calc(var(--wp--style--root--padding-right) * -1);
margin-left: calc(var(--wp--style--root--padding-left) * -1);
}
In my example theme, 1 rem is 16 pixels, and the computed margin for the full width block is:
margin-inline-end -16px
margin-inline-start -16px
margin-left -16px
margin-right -16px
Minimum height
Starting in WordPress version 6.2, the group and post content blocks support setting a minimum height via the dimensions panel. This theme.json setting is opt-in. You enable it by setting appearanceTools
to true or with settings.dimensions.minHeight
:
{
"version": 2,
"settings": {
"dimensions": {
"minHeight": true
}
}
}
This setting is separate from the cover block height control. Disabling this feature will not remove the cover block height control.
Position
The position setting is limited to the group block and to two options; default, and sticky:
Position is disabled by default and can be enabled by enabling appearanceTools or with:
{
"version": 2,
"settings": {
"position": {
"sticky": true
}
}
}
Resources
Rich tabor has written a blog post about using custom spacing in block themes: