How to Create Nested Blocks for Gutenberg

The power of Gutenberg lies in its blocks. Everything is a block. 

But the coolest thing I’ve seen that you can accomplish with said blocks is nested blocks

Nested blocks are blocks within blocks. You can have a single level of nesting, or you can even allow multiple levels of nesting – blocks within blocks within blocks.

With nested blocks, you can even set a template, so that when the block is added to the page, all the inner blocks are already there. Further, if you don’t want the blocks inside the main block (the parent) to ever change, you can lock the block. Pretty nifty!

Here’s an example – this is a single block that’s added with a single click of a button:

A nested block in the Gutenberg editor

As with most Gutenberg documentation, it can be difficult to find information on how to use these things. Let’s take a look.

Create a block

First things first, get your block basics all set up. I’m not going to go into details here, but I recommend watching Zac Gordon’s Gutenberg Development course. You can use his example plugin as a start and go from there, or you can copy the requisite files and bits of code into your existing plugin. 

Another good place to start might be create-guten-block, but again, that’s a topic we’ll cover at another time.

Register InnerBlocks

InnerBlocks is available from the wp.editor package. So, we want to pull this in at the top of our block file.

In the same area where you added the other block libraries, such as:

const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;

You’ll want to add the InnerBlocks library. Add the following:

const { InnerBlocks } = wp.editor;

Add InnerBlocks to the edit function

Now that InnerBlocks is available for use, we’ll want to add it to the edit function for the block. We’ll wrap it in a <div> with the block className for CSS targeting.

edit: props => {
	const { className } = props;
	return [
		<div className={className}>
			<InnerBlocks />
		</div>
	];
}

Cool! Your block officially accepts more blocks inside of it.

Save the InnerBlocks content

We want to make sure the editor is able to save the nested blocks and re-load them there when the page is next opened. So, in our save function, we save the content from the InnerBlocks:

save: props => {
	return (
		<div>
			<InnerBlocks.Content />
		</div>
	);
}

Cool! Save your code, then give it a shot. You should be able to add your block, then add other blocks inside your block. 

Set which blocks are allowed

If you want to allow only a certain subset of allowed blocks, you can set that in the <InnerBlocks> component properties.

In the edit function, add a property to InnerBlocks for allowedBlocks, and pass in an array of blocks that can be used.

edit: props => {
	const { className } = props;
	return [
		<div className={className}>
			<InnerBlocks
				allowedBlocks={['core/paragraph']}
			/>
		</div>
	];
},

The example above will allow only new paragraph blocks to be added to the main block. 

If you’re building something special, like a modifiable list of homes for sale, you can build the custom inner block, then set it as the only block allowed in the parent.

Add a nested block template

Block templates are really cool. When your main block is added to the page, it’ll automatically add all the child blocks according to the template. It allows you to set certain types of content and layout within the main parent block right from the get-go.

The block template should be added as a constant to the block file, probably right below where you add the block libraries. The template is a multidimensional array of child blocks. For example:

const TEMPLATE = [
	['my/block', {}, []],
	['my/other-block', {}, []],
]

Each block sits inside its own array and takes three values:

  1. The block namespace, in single quotes
  2. An object of block attributes that you want to set immediately
  3. An array with more nested blocks
    • This allows you to create nested block templates for blocks you don’t necessarily have code control over, like the core/columns block.

Here’s a real-life example:

const TEMPLATE = [
	['core/heading', { placeholder: 'Recipe Title' }],
	['core/columns', {},[
		['core/column', {}, [
			['core/image']
		]],
		['core/column', {},[
			['core/paragraph', { placeholder: 'Enter short recipe description...' }],
			['core/paragraph', { placeholder: 'Enter ingredients...' }],
			['core/button', { text: 'Make this Recipe' }],
			['pinchofyum/listicle-item-attribution']
			]
		]
	]
]];

In that example, the template includes a heading, then a columns block, with two columns. The first column has an image block, and the second has a couple paragraphs, a button, and an attribution section.

Now, we need to add this template to our <InnerBlocks> component. To do this, just add a template property to the component in the edit function:

<InnerBlocks template={TEMPLATE} />

Lock the template

If you want to make sure that the child blocks don’t change, you can lock the template. There are three options for this:

  1. all – Locking the template completely, so that no blocks can be added, removed or reordered
  2. insert – Locking the template partially, so blocks can be reordered, but not added or removed
  3. false – no locking; blocks can be added, removed, and reordered

Again, this is a property for the <InnerBlocks> component in the editor.

<InnerBlocks 
	template={TEMPLATE} 
	templateLock="all" 
/>

Now, my block has a template set that defines the layout, automatically adds all the necessary child blocks, and prevents the child blocks from being reordered, added, or removed.

Neato! Last thing…

Set the parent for strictly child blocks

If a block you’ve made is meant to be used only inside one type of other block, then you can set the parent for that block.

An example is the column block. The core/column block can only be added inside a core/columns block. You can’t add a column randomly to the page – it has to be inside a columns block.

To do this, you’ll set the parent on the child block. You’ll do this where you set the block title, description, category, etc. Add another block property called parent set it to an array containing the block parent name(s).

For example:

title: 'Listicle Item',
description: 'An item for the Listicle block.',
category: 'formatting',
icon: 'shield',
keywords: ['List item'],
parent: ['pinchofyum/listicle'],

Now, this block will only show up as an option when I’m adding a nested block to the parent block (pinchofyum/listicle, in this case).

Nested blocks are cool!

One reason I love the idea of nested blocks is because it allows us to reuse blocks that already exist for new applications. This prevents us from having to rewrite code that’s already been written – we’re keeping DRY here. 

Nested blocks have a ways to go with functionality – or maybe I just haven’t discovered it. Such as – how can I use the InnerBlocks.Content to write structured data to the front end? Can I get access to that content from the main block? If you know how to do this, let me know in the comments. Otherwise, I’ll be working on figuring it out over the next couple of weeks.

Now go build some nested blocks in Gutenberg!

Leave a Reply

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

3 Replies to “How to Create Nested Blocks for Gutenberg”

  1. Muhammad Zohaib says:

    Very helpfull. Thanks