Inner Blocks are Gutenberg Blocks that allow inserting additional blocks within your own block. To understand it even better, imagine a shortcode that wraps the content. This content can then be shown or hidden. You can achieve that inside Gutenberg with Inner Blocks.

Article Changelog:

  • 2020-03-26 – Added new InnerBlocks properties (templateInsertUpdatesSelection, renderAppender, and __experimentalCaptureToolbars), Added CoBlocks Accordion Example.

Gutenberg Inner Blocks

If you’re interested in reading the code behind Inner Blocks, you can check their folder on Github. They are basically a wrapper that allows putting other blocks inside.

How do you use them? First, you need to import them in the file where you’re going to use them.

import { InnerBlocks } from '@wordpress/editor'; // or wp.editor

Then you need to insert this block inside your edit function (this example uses JSX):

edit( { className } ) {
 return (
  <div className={ className }>
   <InnerBlocks />

To show the contents (other blocks) inside of the InnerBlocks component, you need to call <InnerBlocks.Content/>:

save() {
 return (
   <InnerBlocks.Content />


This block (component) also accepts several properties so that you can customize the UX of your block.


This property can be a string or an array containing names of registered blocks. As the property name suggests, this can be used to allow certain blocks only inside of your Inner Blocks component.

In this example, I am allowing only the image block (and all the child blocks).

<InnerBlocks allowedBlocks={ 'core/image' } />

In this example, I am allowing the image block and the paragraph block (and all the child blocks).

Child Blocks?

So, what are these child blocks? These blocks will always be allowed inside of Inner Blocks. You can register child blocks by providing a parent property. For example:

So, if you specifically set a few blocks that are allowed in the Inner Block component, the child blocks will also be available.


The template property is something like a starter content for your Inner Block component. When you add your block, the inner block component will be already filled with the specified blocks.

An interesting and useful thing is that you can also set the attributes within such blocks.

Here is an example of an Inner Block component with 2 paragraphs which have different placeholders.


This property will let the block be updated with all the blocks when a new one is added. If set to false, it will not update the selection of all the blocks.

Default is true.

In many cases, you probably won’t need to change this, but if you are wondering when you would, here are some of the components/blocks in Gutenberg that set this to false.


This property can decide if you can add, remove and move the blocks inside the Inner Block component. Possible options are:

  • all – nothing is allowed
  • insert – you can’t remove or add new blocks, but you can move the existing ones,
  • false – everything is allowed, even if the parent block is locked.

If nothing is set, it will use the locking value of the parent block.


This can be a function or false. Default is undefined (no function defined).

If nothing is defined (not false or function), the component DefaultBlockAppender will be used. The default block will be usually the paragraph block if not configured otherwise in wp.blocks.setDefaultBlockName.

There are also two appenders set under the InnerBlocks component:

  • InnerBlocks.ButtonBlockAppender -> add a “+” button that when clicked will show the block picker menu,
  • InnerBlocks.DefaultBlockAppender -> same as the above DefaultBlockAppender.

You can also pass a different custom function to show an appender:

// Fully custom 
<InnerBlocks renderAppender={ () => ( 
  <button className="bespoke-appender" type="button">Some Special Appender</button> ) 
} />

For example, the Group block has this to show an appender or not:

<Block.div className={ className }>
  <div className="wp-block-group__inner-container">
       ? undefined
       : () => <InnerBlocks.ButtonBlockAppender />

They have a check hasInnerBlocks and if that’s true, then it won’t show the ButtonBlockAppender.


This is false by default. If set to true, when we are editing a block inside of the InnerBlocks, the toolbar of that block will show on the InnerBlocks container (at the top).

How CoBlocks are using InnerBlocks

We will now check the CoBlocks Accordion block to see how they utilize the InnerBlocks for creating accordion items.

First, they only allow their own coblocks/accordion-item block.

Here is how they call this component:

 template={ getCount( count ) }
 allowedBlocks={ ALLOWED_BLOCKS }

The getCount() function does not actually returns the count of blocks, but for every block (accordion item) they have, they create an accordion item block. The default count is set to 1, so the template will always show 1 accordion item.

Accordion Item block

Let’s now see how the Accordion Item works. This block is set to be allowed only as a child block for their Accordion block:

Each Accordion Item is using InnerBlocks as well and here they also use the parameter templateInsertUpdatesSelection. So, when a new block is added to this item, the focus won’t trigger so that the parent block might get focused and the focus will be left as it was before.

 template={ TEMPLATE }
 templateInsertUpdatesSelection={ false }

The template of this item will use the paragraph block when we add an accordion item.

Creating a Premium Content Block

This will be a block that will have the Inner Block component that will be used for adding the premium content. We can also decide if these content will be available for users with unpaid or paid membership.

That way, you could have a content that is displayed to the members and another “teaser” content to the visitors.

In a previous tutorial, I have written an article on Integrating Gutenberg Blocks in Existing WordPress Plugins where you can see how to create a Webpack configuration for your blocks.

For this tutorial, I am going to use the Create-Guten-Block tool. If you have the latest npm, then position yourself inside of the plugins folder and run:

npx create-guten-block inner-blocks
cd inner-blocks
npm start

You can also open the folder inner-blocks in your editor and change the plugin information. After that, activate your new plugin.

Registering the Block

Open now inner-blocks/src/block/block.js and edit the information to match this:

We have changed the slug of it and added a new attribute paid. This will hold the value true or false and it will indicate if this content is for members or visitors.

The Edit Function

The edit function is the one that will be called to render the Block inside of the Gutenberg editor. In this function we will call the Inner Block component.

We are using the InspectorControls to render the setting in the block settings. With the SelectControl component, we are rendering the options. With onChange attribute we are setting the attribute paid when we select a different value.

The Save Function

This function is used for the content that is saved inside of the post content. Since we will also register our block with PHP, the save function will be used only for rendering the content that we will hide or show.

Dynamic Block Content

To have a dynamic block content, we need to register the block inside of PHP. Open src/init.php and add this:

We also need to define the function that will now process the block content. This can be also an existing shortcode function if you have one.

The Code

With this file, you’ll get the complete plugin in the development mode. You would need to run npm build to build the JavaScript for production. Also, inside of this code, you’ll see a child block example and also the usage of template and allowedBlocks properties.

This part is available only to the members. If you want to become a member and support my work go to this link and subscribe: Become a Member


With the usage of inner blocks component, we can replace all the available shortcodes that are wrapping the content.

Become a Sponsor

Posted by Igor Benic

Web Developer who mainly uses WordPress for projects. Working on various project through Codeable & Toptal. Author of several ebooks at


  1. I’m able to successfully create an inner block and restrict it to core/paragraph – but when I try to restrict it to core/image, the inner block isn’t showing in the editor.


    1. Interesting. Maybe my example is wrong here. Have you tried allowing it as a string or as an array? allowedBlocks={ 'core/image' } or allowedBlocks={ [ 'core/image'] }?


  2. I’ve tracked it down, and it’s a known issue:

    If you’re restricting to allowed blocks, you have to allow paragraph in order for the other allowed blocks to work.


  3. We have this scenario a lot:

    > Lorem ipsum some text [shortcode]affected text[/shortcode] more text, all within one parapgraph.

    How can this be solved with Gutenberg?


    1. That’s an even more complex situation and I am not sure this is something that can be done with Inner Blocks.

      The shortcode should run even if it’s written inside of the parapgrah block.


      1. That’s a standard example from Shortcode API documentation, so I would expect that maybe some people are using this: -> caption_shortcode

        Seems we have to continue using inline “manual” entered shortcodes within Gutenberg blocks, and not the supplied Shortcode block… will be interesting to explain this to customers :-/


  4. Thanks for the tutorial. I wonder if there is a way to use an Innerblock with a ServerSideRender component? Something like:

    edit: function( props ) {
    return [
    // rendering in PHP
    // return :
    el( ServerSideRender, {
    block: ‘test/container’,
    attributes: props.attributes,
    } ),


    // rendering in PHP
    save: function() {
    return null;


  5. Thanks a lot. Is there any way to define custom styling from the available styles of block while declaring template? For example apply particular style on button instead of default.


    1. Hi Ahmad,

      each block has a custom class added to it. If the block does not specify to not use their default class names, then Gutenberg will add the class in the form of .wp-block-{BLOCK NAME}. You can read about it here: (search for className).


  6. Extremely complicated. Can’t this be a plugin for the common human?


  7. The template I’m using for my innerblocks element has group with columns in it. It seems the allowedBlocks attribute only applies to the uppermost container! I can only put things I’ve allowed alongside the group, but inside the columns it’s free game.

    I’m wondering if you can cascade that permission somehow?


  8. Thank for sharing the article. I want to know if you have any ideas on how to use a Blacklist for what kinds of blocks are allowed in the Inner HTML?


  9. Great content!

    I created a custom block for author bio and i have included the social icons built-in block into my custom block using in edit function

    and to display social icons in the frontend i have used

    it working good only in the editor and does not appear in the frontend

    How to make it appear in the frontend


Leave a reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.