WordPress offers many ways to style blocks. In this lesson I want to talk about registering block style variations and section styles that helps users select premade designs.
The custom block styles, often called block style variations, are options in the Styles section of the block settings sidebar. You use them to quickly apply styles without having to adjust individual settings.
Common examples of block styles are the filled and outlined buttons and the rounded image:

Block styles can help users overcome decision fatigue. They can inspire users by offering different premade design, and help us work faster by avoiding repetitive tasks.
What is the difference between block styles, section styles, and global style variations?
Block styles in this context are style variations for one or more blocks. To use the style, you insert the block and then select the style option in the block’s settings sidebar.
Section styles is the exact the same thing, except the styles are also applied to nested blocks and elements.
For example, if you have a group block with a heading, image and paragraph, you can use a single block style to only style the heading, or you can use a section style to style all the blocks inside the group.
You can combine patterns and section styles. That way, users can insert patterns and then quickly change the colors, spacing and typography.
Global, or site style variations changes the whole site, not only single blocks. This is what you use when you want the user to be able to choose between different body background colors. There is a separate lesson for this type of variation.
How do custom block styles work?
When you create your block styles you can choose between adding custom CSS, using a theme.json style variation, or registering an array of style data using PHP. The two latter options are available from WordPress 6.6, and I describe each option below.
Block styles work by generating and adding a CSS class to the block and applying the styles to the new selector. When you have selected a block style in the editor, you can open the Advanced section of the block settings sidebar and see that WordPress adds the class in the Additional CSS class(es) field. WordPress automatically loads the CSS in the editors and the front (unless you choose to register your style using a stylesheet; then you must enqueue it yourself).
It is important to know that these block styles are only an extra layer of CSS on top of the block’s default style. It does not remove the default style, it overrides it using a higher CSS specificity.
It also does not change any other block attributes. If you register and select a style that adds a background color to a block, then it will not be reflected in the block’s background color control.
If you decide to use the background color control to add a new color, this setting will override both the default block style and the style variation.
You are not limited to styling blocks from WordPress core. If you know the prefix and the slug, you can also style blocks from plugins.
How to register custom block styles
You can register the custom block style with PHP, JavaScript or JSON (from WP 6.6). Which method you choose depends on personal preference and how you wish to organize your theme files.
Registering block styles using JSON
To register a style with JSON, you need to have basic knowledge about theme.json.
This feature requires WordPress 6.6 and version 3 of theme.json.
You have to place each custom block style in its own JSON file, or WordPress can not parse them correctly. Place the JSON file inside a folder in your theme called styles, or a subfolder to styles:
styles (dir)
blocks (dir)
sub-heading.json
theme.jsonIn this file, you can only use the styles section, not settings, patterns, templates etc.
There are two key and value pairs that are unique to the block style variations:
- slug: The unique identifier that WordPress uses to create the CSS class.
- blockTypes: The list of blocks that you want to apply the style to.
The title is the the visible label in the editor. Note that long titles are truncated and may not show in the interface.
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"title": "Sub heading",
"slug": "custom-sub-heading",
"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-sub-heading-x”, where x is a unique identifier, or counter.
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-sub-heading--2In this example I am adding the same style to multiple blocks by adding multiple blockTypes:
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"title": "Post meta",
"slug": "custom-post-meta",
"blockTypes": [ "core/post-author-name", "core/post-date", "core/post-terms" ],
"styles": {
"color": {
"text": "#444"
},
"typography": {
"fontSize": "var(--wp--preset--font-size--small)"
}
}
}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 restraint 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.
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"
}
}
}
}
}
}Registering block styles using PHP
You can use the PHP function register_block_style() to create a single block style or a section style. Place the function in your themes functions.php file, or use a separate file if you prefer. You need to use the function with the init hook.
The parameters of register_block_style are:
- block_name: the block name including the name space, for example “core/paragraph”, From WordPress 6.6, this parameter also accepts an array of block names.
- style_properties: an array with required an optional properties:
- name: the unique identifier for the style (required). In the JSON equivalent, this is the slug for the style.
- label: the visible label of the style in the interface (required).
- style_handle: If you want to enqueue custom CSS from a separate stylesheet, you add the name of the style sheet here (optional). Note that you must enqueue the stylesheet in the editors and the front yourself.
- inline_style: If you want to add CSS inline, you add your CSS here, including the selector (optional).
If you are reading this lesson before WordPress 6.6 is released, the official documentation has not been updated yet. The new parameter added to the style properties in WordPress 6.6 is called style_data. You would only use of either style_handle, inline_style, or style_data.
The style data is an array of nested styles in a format that very closely resembles the styles section of theme.json. At the root level, the styles are applied to the block that you defined with the block_name. You style nested blocks and elements by adding them as keys to the array (See the code examples further down on this page).
Examples
First, you need to tell the function which block you want to style. In this example, I am using the core paragraph block. Add the prefix, core, and paragraph (the slug for the block), as the first argument:
register_block_style(
'core/paragraph',
Or, if you want to register the same style for more than one block, you need to use an array:
register_block_style(
array( 'core/paragraph', 'core/heading' ),
You are not limited to styling blocks from WordPress core. If you know the prefix and the slug, you can also style blocks from plugins.
The second argument is an array where you will add the name, which is used in the CSS class that identifies your style, and the label, which is the visible name in the block settings sidebar.
Using an inline style:
function prefix_register_block_styles() {
register_block_style(
array( 'core/paragraph', 'core/heading' ),
array(
'name' => 'prefix-rounded-corners',
'label' => __( 'Rounded corners', 'textdomain' ),
'inline_style' => '.is-style-prefix-rounded-corners {
border-radius: 4px;
background: #fafafa;
}',
)
);
}
add_action( 'init', 'prefix_register_block_styles' );Using a style handle:
function prefix_register_block_styles() {
register_block_style(
array( 'core/paragraph', 'core/heading' ),
array(
'name' => 'prefix-rounded-corners',
'label' => __( 'Rounded corners', 'textdomain' ),
'style_handle' => 'prefix-rounded-corners',
)
);
}
add_action( 'init', 'prefix_register_block_styles' );Using style data for a single block:
function prefix_register_block_styles() {
register_block_style(
'core/group',
array(
'name' => 'prefix-green-background',
'label' => __( 'Green background', 'textdomain' ),
'style_data' => array(
'color' => array(
'background' => 'green',
),
)
)
);
}
add_action( 'init', 'prefix_register_block_styles' );Just like in the JSON style variation, you can use any valid CSS value. In this example I used a plain color name for the background, but you could also reference a CSS custom property.
Using style data for section styling (nested blocks and elements):
function prefix_register_block_styles() {
register_block_style(
'core/group',
array(
'name' => 'section-1',
'label' => __( 'Info', 'textdomain' ),
'style_data' => array(
'color' => array(
'background' => '#fafafa',
),
'blocks' => array(
'core/heading' => array(
'color' => array(
'background' => '#111',
'text' => '#fff',
),
),
),
)
)
);
}
add_action( 'init', 'prefix_register_block_styles' );function prefix_register_block_styles() {
register_block_style(
'core/group',
array(
'name' => 'section-2',
'label' => __( 'Info (alt)', 'textdomain' ),
'style_data' => array(
'color' => array(
'background' => '#111',
'text' => '#fff',
),
'elements' => array(
'h2' => array(
'color' => array(
'text' => '#fafafa',
),
),
),
)
)
);
}
add_action( 'init', 'prefix_register_block_styles' );If your CSS is complex, you may also need to escape certain characters:
'inline_style' => '.wp-block-separator.is-style-prefix-ornament {
mask-image: url(\'data:image/svg+xml; utf8, <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 81.52 29.9">
<path ... /></svg>\' );
}',Registering block styles using JavaScript
Registering a custom block style with JavaScript is a two step process. You first need to register the style so that the option is available in the editors, and then enqueue the stylesheet in the editors and the front. This is why it is less common to use this method.
Create a new JavaScript file and enqueue it together with the following dependencies:wp-blocks, wp-dom-ready, and wp-edit-post. Without these dependencies, your style with not work correctly.
Instead of using wp_enqueue_scripts, you need to use enqueue_block_editor_assets to load the scripts in the editors.
Example adapted from the official documentation:
function prefix_register_variations() {
wp_enqueue_script(
'prefix-block-variations',
get_stylesheet_directory_uri() . '/assets/js/variations.js',
array( 'wp-blocks', 'wp-dom-ready', 'wp-edit-post' ),
filemtime( plugin_dir_path( __FILE__ ) . '/assets/js/variations.js' )
);
}
add_action( 'enqueue_block_editor_assets', 'prefix_register_variations' );If you are not familiar with filemtime, the purpose here is to create a version number for the file used for development.
Create the JavaScript file variations.js and register the style using wp.blocks.registerBlockStyle with the block name, the unique identifier, and the visible label:
wp.blocks.registerBlockStyle( 'core/quote', {
name: 'fancy-quote',
label: 'Fancy Quote',
} );Add your CSS to a stylesheet that you enqueue in both the editors and the front. Remember that the generated CSS selector is is-style-, followed the value of name: is-style-fancy-quote.
How to unregister block styles
You can also unregister block styles. -This is a bit trickier than it needs to be, in my opinion: Styles registered with PHP can only be unregistered with PHP. Styles registered with JavaScript can only be unregistered with JavaScript.
To unregister a style with PHP, you need to use the function unregister_block_style(). Include the prefixed block name (the slug), and the name of the style:
unregister_block_style( 'core/heading', 'prefix-rounded-corners' );Depending on how the style is registered, you need to use an action hook that runs after the one used for the registration; Another reason why unregistering styles can be complicated. -You may need to search the source code to find when the style is registered.
Below is a JavaScript example from the advanced theme that I am using in the block theme generator:
function full_site_editing_unregister_block_style() {
wp_enqueue_script(
'full-site-editing-unregister',
get_stylesheet_directory_uri() . '/assets/js/unregister.js',
array( 'wp-blocks', 'wp-dom-ready', 'wp-edit-post' ),
FULL_SITE_EDITING_VERSION,
true
);
}
add_action( 'enqueue_block_editor_assets', 'full_site_editing_unregister_block_style' );The JavaScript code in unregister.js:
wp.domReady(() => {
wp.blocks.unregisterBlockStyle('core/quote', 'large');
wp.blocks.unregisterBlockStyle('core/quote', 'plain');
});Naming
As you can see from the examples, I have used some different naming principles when adding the unique identifier (name if you are using PHP, and slug if you are using JSON).
The format for the generated class name is is-style- followed by the value that you added to the name property: If the name is ‘section-1’, then the CSS class is ‘is-style-section-1.
There is no way to remove or customize ‘is-style-‘
I recommend using the names section-1, section-2 etc, for section styles to make it easier for users to switch themes. When a user applies a style, the class name is saved in the content in the WordPress database, and using the same class names improves the interoperability between our themes, and the user experience.
You can read discussions about naming custom styles on GitHub:
https://github.com/WordPress/gutenberg/issues/63036
https://github.com/WordPress/twentytwentyfive/issues/3
Additional notes
I have received questions about whether it is possible to select two block styles, but this is still not possible as of July 5, 2024. You can follow the discussion and progress on allowing multiple block styles here: Gutenberg #14598
Resources
Section Styles (The introduction post/dev note on WordPress.org)
Styling sections, nested elements, and more with Block Style Variations in WordPress 6.6