Gutenberg blocks: Add custom default class names

How can I create custom classes to individual Gutenberg blocks?

When I started with the new WordPress block editor was this one of my first questions. By default, not all the post elements have one.
For me is the lack of consistency one of the reasons that I want default class names to the HTML elements inside the post.

Today we focus on the block elements with no class attributes at all.

Before we start
Have you created your own Gutenberg blocks plugin before? If not, go to create-guten-block for a super quick start.

We need some test content

First, we create a new post with some example block elements.

  1. paragraph <p></p>
  2. heading <h2></h2>
  3. list <ul></ul>
Three new Gutenberg block items added.

After publishing the post, we’ll see this on the frontend.

View created items in the browser.

Now we inspect the created elements in Google Chrome.

Inspect created elements in Google Chrome.

As you can see all the elements we created have no class attributes.

Add classes to blocks inside the Gutenberg editor.

Before we are going to use the filter, very quick an example of the default WordPress method to give an element a class.

Add class to a single Gutenberg block.

Our unordered list item gets the class name some-class.

View class name with inspect element in Google Chrome.
Remark that nested items still have no class attribute.

This method is, for example, helpful in situations when you want a different styling for a specific element.

However, if you want a custom class name by default, this is not the right solution.

Custom classes to blocks with no default class names

We are going to use the filter blocks.getSaveContent.extraProps and put all our code in a function called setExtraPropsToBlockType.

Use the create-guten-block plugin if you have no idea what to do with the code. Place it in src/blocks.js.

const setExtraPropsToBlockType = (props, blockType, attributes) => {
    const notDefined = (typeof props.className === 'undefined' || !props.className) ? true : false

    if ( === 'core/heading') {
        return Object.assign(props, {
            className: notDefined ? `post__heading-${props.tagName}` : `post__heading-${props.tagName} ${props.className}`,

    if ( === 'core/list') {
        return Object.assign(props, {
            className: notDefined ? `post__list-${props.tagName}` : `post__list-${props.tagName} ${props.className}`,
            value: attributes.values.replace(/<li>/g, `<li class="post__list-item is-item-${props.tagName}">`),

    if ( === 'core/paragraph') {
        return Object.assign(props, {
            className: notDefined ? 'post__paragraph' : `post__paragraph ${props.className}`,

    return props;

Now, we gave each element his own, default class name.
And we also thought about the <li> items inside our list.

Then we go back to our post in the admin panel and (hard) refresh the page.

Gutenberg blocks with the message: This block contains unexpected or invalid content.

For each block, we got the message “This block contains unexpected or invalid content.” and some options to choose.

You always get this screen when you changed something from an already created element.

We have now two options:

  1. Delete each item and create new ones.
  2. Resolve or convert to HTML.

First we click on the Resolve button.

Resolve block with convert options.

Then we click on Convert to Blocks.

We repeat this action for each block element and save the page.

Sometimes you get unexpected results when you try to convert the content.
In those situations, it’s much easier to copy the content, delete the block and create a new one.

When we inspect the elements again in Chrome, we’ll see that now each element has its own class name.

View created class names with inspect element in Google Chrome.

That’s it for now.

Soon I want to come with a new post to explain how to edit or remove classes from blocks with predefined ones.