One of the most versatile components that Gutenberg block developers have is the <InnerBlocks/>
component. This component allows other blocks to be inserted into it. WordPress Core ships with the Group and Columns blocks that both use InnerBlocks internally to allow the creation of very complex block structures.
The InnerBlocks component solves some interesting problems for custom blocks, for example creating a list of ordered items. By leveraging InnerBlocks, one can skip having to build a bespoke system and rely on Gutenberg to handle the insertion, deletion, and ordering of items. It is very flexible and easy to use. However, while working with it I discovered that there is no built-in way to limit the number of blocks that can be inserted.
The renderAppender prop will allow us to solve this issue
RenderAppender Overview
Before we talk about the solution, let briefly discuss the renderAppender prop and how it works.
Released with WordPress. 5.3, the renderAppender
prop allows us to control the interface for inserting blocks into the related <InnerBlocks/>
component.
There are two predefined appenders available in WordPress core:
<InnerBlocks.DefaultBlockAppender />
<InnerBlocks.ButtonBlockAppender />
As the name indicates, this is the default appender. If the renderAppender
prop is undefined
, then this is the appender that is used. It automatically inserts whichever block is configured as the default block via wp.blocks.setDefaultBlockName
– which by default is the Paragraph block.
If you’ve worked in the block editor at all you’ve already seen this.
So when working with <InnerBlocks/>
, you don’t need to pass anything to renderAppender
to get this style of appender. If fact, you can leave it off entirely.
<InnerBlocks />
This appender is displayed as a + ( plus ) icon button that, when clicked, displays the block inserter. This appender does not insert a default block.
This appender is seen in the Group or Columns block.
To use this in your <InnerBlocks
/>, you have to pass a function to renderAppender
that returns the <InnerBlocks.ButtonBlockAppender />
component.
<InnerBlocks
renderAppender={ () => (
<InnerBlocks.ButtonBlockAppender />
) }
/>
No appender at all
The last option is to pass false
to renderAppender
to not display any appender at all.
<InnerBlocks
renderAppender={false}
/>
Solution
Now that we have an understanding of how the renderAppender
prop works, let us use it to solve the problems of limiting the number of blocks allowed.
After some experimentation, the actual solution is fairly straight forward, we just need a way to count how many blocks have been inserted and if it’s more than we want, we set renderAppender
to false
so that nothing is displayed and the user cannot insert any more blocks until one is removed.
The core/block-editor
datastore provides a getBlock()
selector that we can use to get the information we need. We pass it the clientId
of our block and we can get the list of innerBlocks
, count them, and either display the appender or return false.
Below is the code that you would place into the edit
property of a block, it’s very simple and but demonstrates the the solution.
import { useSelect } from '@wordpress/data';
import { InnerBlocks } from '@wordpress/block-editor';
const InnerBlockWithLimit = ( props ) => {
const { clientId } = props;
const innerBlockCount = useSelect( ( select ) => select( 'core/block-editor' ).getBlock( clientId ).innerBlocks );
const appenderToUse = () => {
if ( innerBlockCount.length < 10 ) {
return (
<InnerBlocks.ButtonBlockAppender/>
);
} else {
return false;
}
}
return (
<InnerBlocks
renderAppender={ () => appenderToUse() }
/>
)
}
Have you seen any other issues when working with <InnerBlocks/>
or want to discuss this approach? If so, leave a comment below!
The post Limiting the block count for InnerBlocks appeared first on Ryan Welcher.
Top comments (0)