Block Styles in Gutenberg

Every block type in the WordPress editor can have multiple style options. Some block types already have style options like buttons and quotes.

I’ll show you how to add and remove style options from blocks.


Block styles let writers easily change the look of a block without any code. When editing a block with available styles, click the “Transform” icon in the top left to change styles.

Here are the style options available in my theme for the quote block:

This is a standard blockquote.

Citation

This is a large quote. It has a CSS class of “is-style-large”

Citation

They are technically just CSS classes added to the block. By using the Block Styles UI for previewing and selecting different styles, your clients won’t need to remember specific class names.

You can add block styles to any block type in Gutenberg: core blocks and custom blocks from plugins. See my note at the bottom on finding the block name so you can attach your custom styles to it.

Adding a script to the editor

We’ll need to create a JavaScript file in your theme or plugin and load it in the block editor. You can use the enqueue_block_editor_assets hook to load assets into the block editor. It works the same as using wp_enqueue_scripts to load assets into the frontend of the site.

Create an empty editor.js file in the directory /your-theme/assets/js/. Then add the following to your theme’s functions.php file:

/**
 * Gutenberg scripts and styles
 * @link https://www.billerickson.net/block-styles-in-gutenberg/
 */
function be_gutenberg_scripts() {

	wp_enqueue_script(
		'be-editor', 
		get_stylesheet_directory_uri() . '/assets/js/editor.js', 
		array( 'wp-blocks', 'wp-dom' ), 
		filemtime( get_stylesheet_directory() . '/assets/js/editor.js' ),
		true
	);
}
add_action( 'enqueue_block_editor_assets', 'be_gutenberg_scripts' );

Adding Block Styles

I’m working on a website with two styles of headings.

In my editor.js file I’m adding “Default” and “Alternate” style options:

wp.domReady( () => {

	wp.blocks.registerBlockStyle( 'core/heading', [ 
		{
			name: 'default',
			label: 'Default',
			isDefault: true,
		},
		{
			name: 'alt',
			label: 'Alternate',
		}
	]);
} );

When a style is selected, a class of .is-style-{name} is applied to the block. So in my stylesheet, the h2 { } has my default styling and h2.is-style-alt { } has my alternate style.

Why register a default style?

The block style selector lets you select which style you want applied, but does not let you unselect one after you’ve picked a style. If you register just one style and then select it for a block, there’s no way to unselect that block style option and return back to the default styling.

I register an extra style option called “Default” or “Regular”, but don’t add any specific styles for that style option. When a user selects the “Default” style for an h2, it uses the h2 {} styling rather than a more specific h2.is-style-default{ }.

If you add isDefault: true then this style will be marked active on blocks that don’t already have a style specified.

Removing block styles

When styling buttons in the Gutenberg block editor, I usually don’t want the style options that come standard with WordPress: rounded, square, and outline.

You can use unregisterBlockStyle to remove existing block styles from a block. Add the following to the editor.js file described above:

wp.domReady( () => {
	wp.blocks.unregisterBlockStyle(
		'core/button',
		[ 'default', 'outline', 'squared', 'fill' ]
	);
} );

I’ll often remove the defaults and then load my own button style options:

wp.domReady( () => {
	wp.blocks.unregisterBlockStyle(
		'core/button',
		[ 'default', 'outline', 'squared', 'fill' ]
	);

	wp.blocks.registerBlockStyle(
		'core/button',
		[
			{
				name: 'default',
				label: 'Default',
				isDefault: true,
			},
			{
				name: 'full',
				label: 'Full Width',
			}
		]
	);
} );

You can also remove blocks entirely from the editor.

List of block names

You need to know the full block name in order to attach or remove styles from it. Here’s a list of all the core blocks as of WordPress 5.4 (excluding all the embed ones):

  • core/archives
  • core/audio
  • core/button
  • core/buttons
  • core/calendar
  • core/categories
  • core/classic
  • core/code
  • core/column
  • core/columns
  • core/cover
  • core/file
  • core/latest-comments
  • core/latest-posts
  • core/legacy-widget
  • core/gallery
  • core/group
  • core/heading
  • core/html
  • core/image
  • core/list
  • core/media-text
  • core/more
  • core/navigation
  • core/navigation-link
  • core/nextpage
  • core/paragraph
  • core/preformatted
  • core/pullquote
  • core/quote
  • core/rss
  • core/search
  • core/separator
  • core/shortcode
  • core/social-link
  • core/social-links
  • core/spacer
  • core/subhead
  • core/table
  • core/tag-cloud
  • core/text-columns
  • core/verse
  • core/video
  • core/widget-area

Finding a block’s name

A simple way to find the block name is to insert the block in a page and then print out an escaped version of post_content to see what’s stored.

I’m using ea_pp() below (code here) but you could also use print_r().

/**
 * Display Post Blocks 
 *
 */
function ea_display_post_blocks() {
	global $post;
	ea_pp( esc_html( $post->post_content ) );
}
add_action( 'wp_footer', 'ea_display_post_blocks' );

Bill Erickson

Bill Erickson is the co-founder and lead developer at CultivateWP, a WordPress agency focusing on high performance sites for web publishers.

About Me
Ready to upgrade your website?

I build custom WordPress websites that look great and are easy to manage.

Let's Talk

Reader Interactions

Comments are closed. Continue the conversation with me on Twitter: @billerickson

Comments

  1. Matt Whiteley says

    Hey Bill – have you found a way to target a style to a specific header (IE an H2) only?

    • Bill Erickson says

      No, but you could just not change anything if they selected the style for a non-supported heading. IE, only style h2.alt.

  2. Joy says

    You are writing about styles, and yet this page is partially unstyled. I see this page as yellow, which is my browser’s default background color. You really ought to style foreground and background together, to ensure legibility.

    • Bill Erickson says

      Interesting! I’ve been building websites for 15 years and I never knew browsers could have a non-white default background color. You learn something new everyday!

      I’ve just updated the styles on my site to add body{ background: #fff; }. Let me know if that fixes the issue for you.

  3. Shane says

    Hey! Love the articles and just finished reading your ACF + Gutenberg article which got me off the ground with blocks. What i’m stuck on is, I used render_callback() because i’m using Timber to render the template pages and it shows up nice on the front end and in the preview, but in the editor is shows up as the standard ACF Rows/List which makes it hard to use in The Block Editor, any idea on how to get my styles markup intocthe block editor? I have also enqueued my styles on the enqueue_block_assets() hook so it will use the styles for both the backend and frontend, i just can’t seem to get it working in the editor. 😞Thanks again!

    • Bill Erickson says

      It sounds like you have the mode set to ‘edit’ so it always renders like an ACF metabox in the backend. If you set it to ‘auto’ it will render like the frontend until selected, then become an editor. If you set it to ‘preview’ it will always render like the frontend and you can edit its settings in the sidebar.

      • Shane says

        Ah, thank you! Now we’re rocking. Last thing, Is it possible to edit the content of the styled blocks in the editor? As in, is it possible to edit the paragraph while seeing the style as it would be output? Trying to avoid using the tiny crammed sidebar for acf content entry. If they could edit directly in the styled block, that would be ideal.

        • Bill Erickson says

          ACF uses dynamic (PHP-driven) blocks so you don’t get the native editing experience like you do with the core blocks.

          The only way to see the content live refresh as you edit it is to use ‘preview’ mode and edit in the sidebar. For more complex blocks, you’re better off using the ‘auto’ mode and using the metabox-looking editor, then you can see the preview version when you select a different block.

  4. Shane says

    Ohhh ok, that’s why it puts it in the sidebar. I was wondering the decision behind that. Knowing that core blocks have that ability I may just take the deep dive into js for a few blocks to see how they achieve that. Thank you again, very helpful information!

  5. Sean says

    This post was super helpful!

    I am using Elementor Pro’s Theme Builder capability and have laid out my new site using custom templates that I’ve built.

    It works great and is fast which I’m happy about.

    But I’m using Gutenberg for creating the content of posts and pages, so the Elementor Template styles the content.

    By adding in that alternative block style, I was able to add a single line of CSS to my post content template in Elementor and now whenever I add a Header Block, I can just select the “alternative” style and get the top margin that I want.

    It’s given me the best of both worlds – thanks, Bill!

  6. Tobias says

    Great article. Let me just share a quick note on the current state of block styles for ALL blocks:

    In theory, adding styles to any block is possible. However, it’s not working for all block types in practice right now. I wanted to add a block style to the core/media-text block and received an error message once I clicked on the styles panel. It turned out, that there is a major bug that keeps devs from adding block styles to blocks with inner blocks (such as media-text, columns, etc.).

    For those who have the same problem and want to get news around the bug fix, there is already a story on GitHub: https://github.com/WordPress/gutenberg/issues/9897

  7. Pat Quintin says

    This is so helpful! I’ve been able to add some class name options to headings, columns, paragraphs, and galleries – but not images or videos…?? Do you know anything about that?

    Also, I had to chuckle at your comment about browser backgrounds – modern browsers mostly default to white, but the default used to be gray, so setting a bg color was one of the first things I learned to do. On the body tag! (bgcolor=”#ffffff” – you kids get off my lawn!)

  8. Alan Shapiro says

    Thanks for this article, Bill. As always, your explanations are clear and helpful. Two questions: (1) Can block styles be added conditionally? For example, I want certain paragraph styles to be available only for post, not for pages. (2) How would you code these to be styles added by toggle, like the toggle that’s used to add the drop cap style to a paragraph in “Text Settings”?

    • Bill Erickson says

      Those are great questions.

      1. I think it’s technically possible, but I’m not familiar enough with the JavaScript API to figure it out. You would use the wp object to access the post data in some way.

      2. This wouldn’t use the Block Styles feature, but would require registering your own custom ToggleControl in the Gutenberg editor, then add JS to toggle the class on the block. Take a look at this file for how the drop cap toggle is being added.

    • Bill Erickson says

      I pinged Justin Sainton who is a JavaScript expert, and he showed me how to access the post type.

      The following code will register a “Custom Page” block style for paragraphs on pages only:

      wp.domReady( () => {
      
      	const { getCurrentPostType } = wp.data.select( 'core/editor' );
      	let postType = getCurrentPostType();
      	if( 'page' === postType ) {
      		wp.blocks.registerBlockStyle( 'core/paragraph', {
      			name: 'custom-page',
      			label: 'Custom Page',
      		});
      	}
      
      } );
      
  9. Jonas Merhej says

    More than one style can be registered in the following way:

    wp.blocks.registerBlockStyle( ‘core/paragraph’, [
    {
    name: ‘style one’,
    label: ‘Style One’,
    },

    {
    name: ‘style two’,
    label: ‘Style Two’,
    },
    ] );

    rather than doing this:
    wp.blocks.registerBlockStyle( ‘core/button’, {
    name: ‘default’,
    label: ‘Default’,
    isDefault: true,
    });

    wp.blocks.registerBlockStyle( ‘core/button’, {
    name: ‘full-width’,
    label: ‘Full Width’,
    } );

  10. Mats says

    I am trying to remove a block setting, in this specific case the height option for the Spacer block, to replace it with specific styles instead.
    Would it be possible to do that with a similar code?

    • Bill Erickson says

      I don’t believe there’s a way to remove the height option on the spacer block. I personally use the “Separator” block for this type of functionality and have a “Spacer” style for the separator. This ensures all uses of our spacer are the same size.

      You might want to follow or comment on this ticket for updates on changing the UI of the spacer block.