WordPress.org

WordPress Developer Blog

Creating custom block styles in WordPress themes

WordPress introduced the Block Styles API in version 5.3 as a feature for theme authors to create block customizations that are not possible via the built-in design tools. However, it is often an underutilized feature in themes. And, when it is used, the results are sometimes are best replaced with variations or patterns.

In this guide, you will learn what block styles are, when to use them, and how to build them from scratch.

What are block styles?

In essence, a block style is nothing more than a CSS class. Under the hood, this class can be attached to a block’s output to change its design. Like any other class, theme authors can attach any CSS properties and values to it that they want.

Developers can register any number of styles for individual blocks, and WordPress will display them in the block’s sidebar panel in the editor. Users can then select their desired style, such as the “Rounded” design shown in the following screenshot:

Overall, the feature is merely a UI layered over a simple class-based selector.

When to build a custom block style

The general rule of thumb is that block styles should be used when you have exhausted other options and need to rely on custom CSS. Out of the box, most core blocks support an array of design tools, which are generally mapped to existing CSS properties. Over time, this has led to fewer scenarios where custom block styles are necessary.

If you wanted to give an Image block a solid border, there is no need for a custom style for that. WordPress already has built-in options for borders, as shown in the following screenshot:

Theme authors can also use theme.json to define defaults for each of the available options.

What if you wanted to give a “hand-drawn” look to the border? WordPress doesn’t have any options for handling that scenario. It would require some custom CSS. That makes it a good candidate for a custom block style.

This is also one of the most exciting things about theme development. While WordPress has made great strides to create standards, it’s within these standards that creativity can still flourish.

Registering a custom block style

For this tutorial, you will build a custom block style that gives the Image block a “hand-drawn” border, as shown in the screenshot in the previous section. The first step in doing this is using the register_block_style() PHP function.

The following code snippet is a quick look at the function and its parameters:

register_block_style(
    $block_name,
    $style_properties
);

The $block_name parameter should be the name of the block type (e.g., core/image). The $style_properties parameter is an associative array of arguments that can be passed in to configure the style:

  • name: (required) a unique identifier, which is used to generate the CSS class (e.g., is-style-{name})
  • label: (required) an internationalized, human-readable label for the style
  • inline_style: inline CSS to be printed when the style is in use
  • style_handle: the handle of a registered stylesheet to enqueue for the style
  • is_default: whether the style should be selected as the default for the block

Note that style_handle currently has a bug where it only enqueues the stylesheet in the editor but not on the front end. For now, its use is not recommended.

To register a custom style, create a callback function in your theme’s functions.php file and add it to the init action hook. The following code registers the hand-drawn block style:

add_action( 'init', 'themeslug_register_block_styles' );

function themeslug_register_block_styles() {
    register_block_style( 'core/image', array(
        'name'         => 'hand-drawn',
        'label'        => __( 'Hand-Drawn', 'themeslug' ),
        'inline_style' => '.wp-block-image.is-style-hand-drawn img {
            border: 2px solid currentColor;
            overflow: hidden;
            box-shadow: 0 4px  10px 0 rgba( 0, 0, 0, 0.3 );
            border-radius: 255px 15px 225px 15px/15px 225px 15px 255px !important;
        }'
    ) );
}

Theme authors can also register block styles via JavaScript. However, there are likely few or no scenarios where this is necessary. The Block Editor Handbook has a reference page that describes how to do this. The parameters match their PHP counterparts, so the technique is essentially the same—it’s simply in a different language.

Loading styles separately

Using the inline_style option and writing CSS inside of PHP is OK for one-off styles, but it can be messy and become a management headache in the long term. For most scenarios, you will want to manage CSS within CSS files and let WordPress inline it automatically.

First, remove the inline_style property from the function you defined earlier, as shown in the following:

add_action( 'init', 'themeslug_register_block_styles' );

function themeslug_register_block_styles() {
    register_block_style( 'core/image', array(
        'name'  => 'hand-drawn',
        'label' => __( 'Hand-Drawn', 'themeslug' )
    ) );
}

The above will register the block style, but it will no longer have any custom CSS attached to it.

Now, you will create a block-specific stylesheet. WordPress will load its contents and inline the CSS only when the block is in use. For more information on per-block stylesheets, visit Leveraging theme.json and per-block styles for more performant themes.

For this exercise, assume that you have an empty assets/blocks/core-image.css that houses custom CSS for the Image block. To load it only when the block is in use, add the following code to your functions.php file:

add_action( 'init', 'themeslug_enqueue_block_styles' );

function themeslug_enqueue_block_styles() {
    wp_enqueue_block_style( 'core/image', array(
        'handle' => 'themeslug-block-image',
        'src'    => get_theme_file_uri( 'assets/blocks/core-image.css' ),
        'path'   => get_theme_file_path( 'assets/blocks/core-image.css' )
    ) );
}

Then, add the following CSS to the core-image.css file:

.wp-block-image.is-style-hand-drawn img {
    border: 2px solid currentColor;
    overflow: hidden;
    box-shadow: 0 4px  10px 0 rgba( 0, 0, 0, 0.3 );
    border-radius: 255px 15px 225px 15px/15px 225px 15px 255px !important;
}

Unregister block styles

There are scenarios where you might want to remove a registered block style, such as hiding core options or removing something registered by a parent theme or plugin. In most scenarios, you will use the unregister_block_style() function for this.

Let’s suppose you were building a child theme for a theme that registered the Hand Drawn style. You only need to know the block type (core/image) and the style name (hand-drawn). The following PHP code would unregister it:

add_action( 'init', 'themeslug_unregister_block_styles', 15 );

function themeslug_unregister_block_styles() {
    unregister_block_style( 'core/image', 'hand-drawn' );
}

There is one caveat when unregistering block styles: if the style was registered via JavaScript, it must also be unregistered via JavaScript. All of the built-in core block styles will require this method.

Assuming a custom block-editor.js file located in your theme’s assets/js folder, enqueue the JavaScript as shown in the following code snippet:

add_action( 'enqueue_block_editor_assets', 'themeslug_block_editor_assets' );

function themeslug_block_editor_assets() {
    wp_enqueue_script(
        'themeslug-block-editor',
        get_theme_file_uri( 'assets/js/block-editor.js' ),
        array( 
            'wp-blocks', 
            'wp-dom-ready', 
            'wp-edit-post' 
        )
    );
}

Add the following code to your block-editor.js file to unregister the core rounded style on the Image block:

wp.domReady( function () {
    wp.blocks.unregisterBlockStyle( 'core/image', 'rounded' );
} );

Multiple styles per block

An oft-requested addition to the block styles feature is to allow users to select multiple styles. This is not currently supported in WordPress. In some scenarios, it makes sense. Plus, under the hood, block styles are nothing more than a CSS class, and most developers know that there are no limitations on classes that you can add to an element.

However, in practice, multiple block styles could easily clash with one another.

More often than not, block styles that could be combined are simple customizations that might be better relegated to the built-in design tools. WordPress blocks now support a wide range of CSS features that suit such basic needs. And, when those basics need to be combined, perhaps a block variation would be a better choice.

There is an ongoing conversation around multiple styles per block. It is possible this is supported or the feature is extended in some way to allow for more flexibility in the future.

Props to @bcworkz and @mburridge for review and feedback. Photos by @kharisblank, @stephendumba1, and @roytanck from the WordPress photos directory.

6 responses to “Creating custom block styles in WordPress themes”

  1. David Morgan Avatar

    Hey Justin,

    This is great! However, what if I have already created style options for a custom block that were registered under the settings panel before the new styles panel existed? How would I go about moving these options from settings to styles in my custom block?

    For instance, I have a range input for a custom block that controls the border radius for the block. This option would be better suited under the new “styles” panel, but it currently displays under the “settings” panel in my custom block.

    I can’t find any docs explaining how I would associate these options with the new panel?

    Thanks!

    1. Justin Tadlock Avatar

      You’re referring to the new split block tools panel, I believe. That’s actually a great question and one that I found out yesterday. Coming in Gutenberg 15.1 (WordPress 6.2) will be a new group attribute.

      So, when adding your inspector controls, you’d add this attribute like so:

      <InspectorControls group="styles">
      // Add your custom styles related controls here.
      </InspectorControls>

      1. David Morgan Avatar

        Awesome! Man, I was so close, haha. Exactly what I was looking for. Thanks a ton!

  2. sinclairbenj Avatar

    Hi there, would you mind elaborating on:

    “Assuming a custom block-editor.js file located in your theme’s assets/js folder”

    Not sure what this means or if there’s background that could help me figure out how/why to add this js file.

  3. Mike Badgley Avatar

    Excellent article, Justin. One question I had was the possibility of loading custom styles only if that particular block style is being used on a given page, rather than having everything bundled into a single file (i.e. `core-image.css`.

    Ideally one could have additional stylesheets for each custom block style that is defined which are only loaded if/when they are used on a given page. For example, `core-image-custom-handdrawn.css`.

    1. Justin Tadlock Avatar

      The standard method of doing this using the style_handle parameter of register_block_style() is currently broken (and has been for over 3 years). So, it’d probably require a custom solution or to use the inline_style parameter.

Leave a Reply

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