WordPress.org

WordPress Developer Blog

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

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

WordPress 6.6, expected to be released on July 16, 2024, is set to bring the biggest overhaul to block style variations (block styles, for short) in a long while. These changes will make block styles one of the most powerful tools in your theme developer toolbox.

As the 6.6 development cycle wraps up in the coming weeks, you’ll often see these changes referred to as “section styles.” While this is a part of the updated feature set (and I’ll dive into this later in this post), it doesn’t accurately reflect how important this release is for theme authors.

I have already cut 100s of lines of custom CSS code from my theme, transferring it to the standard theme.json file. Being able to place most of my style-related code under a single, standardized system cannot be understated.

On top of that, the new nesting capabilities solve several workarounds that I’ve had to employ in my own theme work (I’ll get into those too).

Let’s just dive right into the updates to the block style variations system.

Customizing block style variations via theme.json

In 2023, WordPress 6.3 introduced the ability to edit Core-registered block style variations via theme.json. This was a nice first step, but it wasn’t an overly exciting upgrade to the theming experience since the power of block style variations is in those that you create yourself. For all intents and purposes, this meant that most use cases required custom CSS.

WordPress 6.6 will let you style any registered block style variations in theme.json. Just like with Core variations, you can target your custom variations via the styles.blocks.blockName.variations property.

I don’t want to downplay the other updates too much, but this change alone is where you’ll cut back the most on custom CSS.

Let’s give it a try. In the screenshot below, you’ll see that I’ve designed a Boxed style variation for the Pullquote block:

As you’ve always done, you’ll need to register custom block style variations via PHP or JavaScript. In this case, you’ll use the PHP method, so first add a registration callback function hooked to init in your theme’s functions.php file:

add_action( 'init', 'themeslug_register_block_styles' );

function themeslug_register_block_styles() {
	// Add calls to register_block_style() here.
}

You’ll use this function for registering custom variations throughout the rest of this tutorial.

Now add this code inside of your themeslug_register_block_styles() function to register the Boxed block style variation:

register_block_style( 'core/pullquote', [
	'name'  => 'boxed',
	'label' => __( 'Boxed', 'themeslug' )
] );

In the past, you may have used the inline_style property of register_block_style() or output some custom CSS in some other way, such as a block stylesheet. But now you can register the style variation and move your actual style code to your theme.json file.

For the Boxed variation, let’s just stick with border and spacing styles (feel free to customize further to match your theme). Integrate the following code into your theme.json file:

{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 3,
	"styles": {
		"blocks": {
		"core/pullquote": {
				"variations": {
					"boxed": {
						"border": {
							"color": "currentColor",
							"style": "solid",
							"width": "6px"
						},
						"spacing": {
							"padding": {
								"top": "var:preset|spacing|60",
								"bottom": "var:preset|spacing|60",
								"left": "var:preset|spacing|60",
								"right": "var:preset|spacing|60"
							}
						}
					}
				}
			}
		}
	}
}

Note that the code for the variation goes directly under styles.blocks.core/pullquote.variations.boxed. You can include multiple variations for each block under its variations property.

The JSON above and throughout this tutorial uses the new version 3 theme.json schema, which is only supported for WordPress 6.6+ or when using the Gutenberg plugin alongside an older version of WordPress.

Styling nested elements and blocks

Being able to add block style variations to theme.json solves a lot of problems on its own, mostly around standardization. But WordPress 6.6 also kicks this up a notch and lets you style elements and blocks that are nested inside of your custom variations. This will open the door to a near-unlimited canvas to paint via theme.json.

Let’s take a look at how this works via a block style variation on the Post Terms (Categories) block. As shown in the following screenshot, you’ll see that the block has the Buttons block style and the individual category links look like buttons:

This design is now possible using theme.json because you can target the link elements nested within the Post Terms block.

To give this variation a test, add this code inside your themeslug_register_block_styles() function in functions.php:

register_block_style( 'core/post-terms', [
	'name'  => 'buttons',
	'label' => __( 'Buttons', 'themeslug' )
] );

Just like in the previous section, you’ll target the variations.variationName property of the block you’re adding the variation to in theme.json. However, to style nested elements, you’ll want to go a couple levels deeper and target elements.elementName.

Integrate the following code into your theme’s theme.json file:

{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 3,
	"styles": {
		"blocks": {
			"core/post-terms": {
				"variations": {
					"buttons": {
						"elements": {
							"link": {
								"color": {
									"background": "var:preset|color|contrast",
									"text": "var:preset|color|base"
								},
								"spacing": {
									"padding": {
										"top": "var:preset|spacing|20",
										"bottom": "var:preset|spacing|20",
										"left": "var:preset|spacing|40",
										"right": "var:preset|spacing|40"
									}
								},
								"typography": {
									"textDecoration": "none"
								}
							}
						},
						"css": "& .wp-block-post-terms__separator { display: none; }"
					}
				}
			}
		}
	}
}

As shown above, the code specifically targets elements.link for the buttons variation. You can also customize nested blocks via the blocks.blockName property for this variation (assuming it supports nested blocks).

You may have noticed that the code included a css property for the variation. Yes, you can add custom CSS for block style variations in your theme.json! In this case, it was used to hide the separator between post terms, targeting this specific variation.

Sections styles and new registration methods

“Sections styles” refer to a concept that is being introduced in WordPress 6.6. In essence, a section is just a block style variation and any nested elements and blocks that you can customize via the theme.json system. 

Wait…isn’t that what was just covered above? Mostly, yes.

But the foundational concepts that led to section styles opened some new features within the block style variations system:

  • You can register new theme.json objects for these variations via:
    • A custom /styles/*.json file.
    • The register_block_style() PHP function.
  • You can register them for multiple blocks at once (e.g., Group, Columns, etc.).

While the new terminology may sound like a fresh marketing spin on an old feature, there are very real benefits. But at the end of the day, it’s just an extension of what’s currently possible with block style variations. 

The primary goal of section styles is to use them for actual sections that need to be designed differently than your primary theme.json styles. Imagine if you wanted to quickly switch between color sets for different sections as shown in this screenshot:

That’s easy enough to do with the design tools in the block inspector (sidebar), but it’s not easy to update across a site when the design changes. That’s where block style variations shine.

And when you mix this with nested element and block designs, you can essentially create full-blown theme.json style sets for specific sections. For example, you could even create section-specific (nested) styles for the Heading, Paragraph, Image, and Blockquote blocks used in either of those sections to make them even more unique.

This can come in handy when creating a standardized, updateable design system for client sites, for example.

Registering block/section style variations

There are two methods of registering section styles, as noted earlier. The primary method is to create a new JSON file under the /styles folder in your theme. This way, you can manage them as separate entities. But follow along to learn how each method works.

Registering via JSON files

In the past, you could only add global style variation JSON files to your theme’s /styles folder, but that is changing in WordPress 6.6. You’ll now be able to add global, block, color, and typography variations to this folder.

To not confuse the different types of style variations, I recommend organizing your /styles folder using a structure similar to this (WordPress will automatically look in sub-folders):

  • /styles
    • /block or /section
    • /color
    • /global
    • /typography

Color and typography style variations are a new feature coming in WordPress 6.6. They’ll be covered here on the Developer Blog, but they are outside the scope of this post.

With this organizational system in mind, create a new /styles/block/section-1.json file and put this code in the file:

{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 3,
	"slug": "section-1",
	"title": "Section 1",
	"blockTypes": [ "core/group", "core/columns" ],
	"styles": {
		"color": {
			"background": "var:preset|color|contrast",
			"text": "var:preset|color|base"
		}
	}
}

This will create the “Section 1” block style variation from the above screenshot (the colors may be different, depending on your theme).

You should also take note of a few key properties defined in the JSON:

  • slug: A unique slug for your section, which can contain alphanumeric characters, hyphens, or underscores. 
  • title: A title for your section that will be shown to screen readers. This is used to automatically register your variation if no slug is present (e.g., Section 1 becomes section-1).
  • blockTypes: An array of block types that this style variation should apply to (you’re no longer limited to a single block type).

This section style is an overly simple example for demonstration purposes. It’s possible to flesh this out to include styles for every element and block that WordPress supports, styling them when they are used within this block. It’s for this reason that these types of variations may best be used for container-type blocks, such as Group, Columns, and Cover.

Now add a /styles/block/section-2.json file in your theme to make a Section 2 block style variation. You can use the following code, but mix up the colors to your liking:

{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 3,
	"slug": "section-2",
	"title": "Section 2",
	"blockTypes": [ "core/group", "core/columns" ],
	"styles": {
		"color": {
			"background": "#cbd5e1",
			"text": "var:preset|color|contrast"
		}
	}
}

Registering via PHP

The third option for registering a section style (or any block style variation) is with PHP. There are two primary changes to the register_block_style() function that make this possible:

  • The first parameter, $block_name, now accepts an array of block types (you can still pass a string for a single block type).
  • The second parameter, $style_properties, has a new style_data key that accepts an array of data that should be formatted like its JSON counterpart.

To register the Section 1 block style variation via PHP instead of JSON, add this code inside your themeslug_register_block_styles() function in functions.php:

register_block_style(
	[ 'core/group', 'core/columns' ],
	[
		'name'       => 'section-1',
		'label'      => __( 'Section 1', 'themeslug' ),
		'style_data' => [
			'color' => [
				'background' => 'var:preset|color|contrast',
				'text'       => 'var:preset|color|base'
			]
		]
	]
);

Of course, you can repeat this process for Section 2 and other custom variations you build.

Overwriting via global style variations

Originally, it was possible to register block style variations via theme.json or custom global style variation JSON files. However, based on ongoing discussions, registering using this method was removed in Gutenberg 18.7 and WordPress trunk.

This method can style be used to overwrite section styles via global style variation JSON files. However, based on the results of the discussion, this could change in WordPress 6.7 and beyond. Keep an eye on the ticket to stay updated.

WordPress 6.6 also adds a new styles.variations property (this property was previously styles.blocks.variations) for overwriting section styles within global style variations.

The difference here is really in the formatting when compared to a block style variation JSON file. You must pass the variation slug (e.g., section-1) as a key and the variation’s styles as the value under the variations property. Take a look at the same Section 1 variation you registered earlier when overwriting it via a global style variation JSON file:

{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 3,
	"styles": {
		"variations": {
			"section-1": {
				"color": {
					"background": "#22737c",
					"text": "#ffffff"
				}
			}
		}
	}
}

A section style with nested block customization

Now, let’s look at a more practical example of section styles that I’ve used in my theme. It customizes nested blocks.

One of the design touches I wanted to add to my theme was to give the Post Author Name block a different font family and style when used in a specific context. It’s a simple thing, but it made me happy. You can see this small design change in the template view in this screenshot (compare the Post Author Name Block’s typography to that of the Post Date and Categories blocks):

I’ve done this by creating a Post Byline block style variation. Then I specifically targeted the Post Author Name block to give it unique typography that looks different from the rest of the blocks used in the byline. I also changed the text-decoration of all link elements for this variation.

To give this a try, create a new file named /styles/block/post-byline.json in your theme. Then add the following code to it (note that you may need to change the fontFamily reference to match one of your theme’s fonts):

{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 3,
	"title": "Post Byline",
	"blockTypes": [ "core/group" ],
	"styles": {
		"elements": {
			"link": {
				"typography": {
					"textDecoration": "none"
				},
				":focus": {
					"typography": {
						"textDecoration": "underline"
					}
				},
				":hover": {
					"typography": {
						"textDecoration": "underline"
					}
				}
			}
		},
		"blocks": {
			"core/post-author-name": {
				"typography": {
					"fontFamily": "var:preset|font-family|primary",
					"fontStyle": "italic"
				}
			}
		}
	}
}

I could showcase dozens of examples of where this has helped me overhaul my theme and take a new approach to styling sections of blocks. But I am limited by the nature of a written tutorial.

I hope that these few examples provide a good starting point for you with your own designs. There is so much more that you can do, and I welcome you to share what you’ve built on top of this new system.

The upgrades to block style variations meant overhauling how Core generated block styles and reducing their specificity. If you have block-specific custom CSS in your theme, there is a chance that these changes will impact your custom styles in some way. But they will also let you use  theme.json for many more use cases.

For a more detailed overview of the changes that led to this update, read the Dev Note: WordPress 6.6 CSS Specificity. You can also dive into the tickets where discussions and changes occurred:

These CSS changes were necessary to push forward with new features and clean up quite a few older issues. On the whole, they should make styling blocks much cleaner and significantly decrease the amount of custom CSS you need.

Props to @ndiego and @colorful-tones for feedback and review on this post.

Categories:

15 responses to “Styling sections, nested elements, and more with Block Style Variations in WordPress 6.6”

  1. Trevor Robertson Avatar
    Trevor Robertson

    Thank you (yet again) for yet another very helpful post Justin! Something that came to mind after reading this — I’ve recently used your tip in a previous post about per-block stylesheets. But as you mentioned in that post the ultimate aim is to use as little custom CSS as possible. Would you now say that being able to style blocks via JSON files reduces the need per-block stylesheets?

    1. Justin Tadlock Avatar

      Absolutely. My general rule is that if it can be done via JSON, it usually should be. This way, it also integrates with the design tools in the interface. So, things like border, color, shadow, spacing, and typography are all easily portable to JSON from block stylesheets.

      Where you really need block stylesheets now are for things are not a part of the standard design tools set. For some themes, that may now mean not needing them at all. For other themes, it could still mean using quite a bit of custom CSS.

      But on the whole, it should greatly reduce the need for block stylesheets for most themes.

  2. Danielle Zarcaro Avatar
    Danielle Zarcaro

    Will this overhaul to the system lead to the ability to enable selecting multiple block styles at once?

    1. Justin Tadlock Avatar

      I doubt that selecting multiple block style variations will be a feature, at least not on its current path. They represent a sort of component system that lets you design the entire section at once (in this case, the entire block or its nested elements/blocks). Combining multiple block style variations wouldn’t really work. Imagine a user selecting both Section 1 and 2 from the above examples. Which colors get applied? Then, apply that same question to every single design tool available and multiply it by any number of style variations.

      It sounds like what you’re after is more of a utility class system where you can mix and match multiple styles. Technically, presets like colors, fonts, and shadows fit into the utility system mold more than block style variations.

      Of course, there is no mechanism for custom utilities at this point. I would recommend opening a ticket in the Gutenberg repository to explore this idea.

  3. leemon Avatar

    Too bad that the CSS property in theme.json you mentioned in your post doesn’t work in classic/hybrid themes. There’s been an open issue (with a PR) on GitHub for a year, but it’s been ignored:

    https://github.com/WordPress/gutenberg/issues/52644

  4. Grégoire Noyelle Avatar

    Hello Justin,
    I love this feature. Thanks.
    Is-it possible to target a pseudo-element (::before…) with `css` ou we should use the automatic class (is-style-slug) instead?

    1. Justin Tadlock Avatar

      Using something &::before { /* your styles */ } will generate the style, but I’m not sure how well that plays with the new :where() wrapper. It would generate CSS like :root :where(.is-style-something::before) { /* your styles */ }. That scenario probably needs some testing. But, generally speaking, I’m putting that code in a stylesheet and targeting .is-style-something::before.

      1. Grégoire Noyelle Avatar

        Thanks, Justin. I tried with this type of rule, but it doesn’t even generate the before or after with the concerned tag. To be continued.

  5. Grégoire Noyelle Avatar

    Hi Justin,
    With the new method (Registering via JSON files), is it possible to use the `settings` object? I tried several parameters, but none of them work.
    Thanks.

    1. Justin Tadlock Avatar

      No, there’s not. Internally, the JSON files are just passed into register_block_style(), and there’s no mechanism for creating settings. Generally speaking, you wouldn’t add settings anyway because these are styles. The only real use case I’ve come up with is settings.custom to create custom CSS properties. Honestly, I feel like those belong under the JSON styles property. We need a ticket for that.

      1. Grégoire Noyelle Avatar

        Thanks again, Justin, for this clarification. I was just thinking that for a variation, it might be possible to remove certain settings (choosing the font or its size).

  6. Grégoire Noyelle Avatar

    Following Brian’s video, I did several tests and the `spacing` options do not work on `core/group`.
    Here is the link to the video:
    https://www.youtube.com/live/EuksXo0olw0?si=8C_VdmhxMatCRjXq&t=2512

    1. Grégoire Noyelle Avatar

      Sorry, that was the `blockGap` option.

  7. Tim Nicholson Avatar

    I’ve been experimenting with your section examples that change the background and text color, but can’t seem to be able to extend it to add some padding. WordPress itself (and most themes) have CSS to automatically add padding to groups with a colored background, but this would be better to be able to specify the padding in the json for the section. I can’t seem to get it to work. I’ve tried both the top level and targeting the group block. Neither works. Is there any documentation on what style properties are supported?

    {
    "$schema": "https://schemas.wp.org/trunk/theme.json",
    "version": 3,
    "slug": "section-1",
    "title": "Section 1",
    "blockTypes": [ "core/group", "core/columns" ],
    "styles": {
    "color": {
    "background": "var:preset|color|light-yellow",
    "text": "var:preset|color|almost-black"
    },
    "spacing": {
    "padding": {
    "top": "var:preset|spacing|40",
    "right": "var:preset|spacing|40",
    "bottom": "var:preset|spacing|40",
    "left": "var:preset|spacing|40"
    }
    },
    "blocks": {
    "core/group": {
    "color": {
    "background": "var:preset|color|orange",
    "text": "var:preset|color|white"
    },
    "spacing": {
    "padding": {
    "top": "var:preset|spacing|40",
    "right": "var:preset|spacing|40",
    "bottom": "var:preset|spacing|40",
    "left": "var:preset|spacing|40"
    }
    }
    }
    }
    }
    }

    1. Justin Tadlock Avatar

      Targeting styles.spacing.padding definitely works, as do every other thing that I’ve added support for (see exception noted above for blockGap).

      My guess (without the full context of what you’re testing) is that you have some other padding that’s overwriting the Group block. Also remember that block-level styles will always overrule global styles.

Leave a Reply

Your email address will not be published. Required fields are marked *