Allows blocks inside a block. Kind of works like the editor itself, just inside a block. Used in the core “Media & Text” block for example. Can also be used to create a connected continuous block as the core “Group” block for example.
Example with the regular InnerBlocks:
import { registerBlockType } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
//styles that make it look good in the editor
import './editor.scss';
const BLOCKNAME = "inner-blocks";
const BLOCKPATH = `wp-gb/${BLOCKNAME}`;
const STYLES = {
boxShadow: "1px 1px 1px 0px rgba(0, 0, 0, 0.4)",
minHeight: 100,
padding: "48px 48px 0 48px",
display: "flex",
alignItems: "center",
justifyContent: "center",
backgroundColor: "white",
color: "black"
};
registerBlockType( BLOCKPATH, {
apiVersion: 2,
title: __( 'Inner Blocks', 'wp-gb' ),
description: __( 'The description' ),
category: 'wp-gb',
icon: 'smiley',
edit: (props) => {
const ALLOWED_BLOCKS = [
'core/image',
'core/paragraph',
'core/columns',
'core/heading',
'wp-gb/inner-blocks'
];
const TEMPLATE = [ [ 'core/columns', {}, [
[ 'core/column', {}, [
[ 'core/image' ],
] ],
[ 'core/column', {}, [
[ 'core/heading', {
level: 3,
placeholder: 'Enter side title...'
} ],
[ 'core/paragraph', {
placeholder: 'Enter side content...'
} ],
] ],
] ] ];
return (
<div { ...useBlockProps({ style: STYLES }) }>
<InnerBlocks
allowedBlocks={ ALLOWED_BLOCKS }
template={ TEMPLATE }
/>
</div>
)
},
save: (props) => {
return (
<div { ...useBlockProps.save({ style: STYLES }) }>
<div>
<InnerBlocks.Content />
</div>
</div>
)
},
} );
Another header and another paragraph to the block then this can be added by clicking on the appender button as the header image illustrated:
The inner block of an inner block can also be an inner block.
RenderAppender
Use the renderAppender prop in order to create a connected continuous block:
import { registerBlockType } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
//styles that make it look good in the editor
import './editor.scss';
const BLOCKNAME = "inner-blocks-appender";
const BLOCKPATH = `wp-gb/${BLOCKNAME}`;
const STYLES = {
boxShadow: "1px 1px 1px 0px rgba(0, 0, 0, 0.4)",
minHeight: 100,
padding: "48px 48px 0 48px",
display: "flex",
alignItems: "center",
justifyContent: "center",
backgroundColor: "white",
color: "black"
};
registerBlockType( BLOCKPATH, {
apiVersion: 2,
title: __( 'Inner Blocks With Appender', 'wp-gb' ),
description: __( 'The description' ),
category: 'wp-gb',
icon: 'smiley',
edit: (props) => {
const ALLOWED_BLOCKS = [
'core/button'
];
const TEMPLATE = [ [ 'core/button' ] ];
return (
<div { ...useBlockProps({ style: STYLES }) }>
<InnerBlocks
allowedBlocks={ ALLOWED_BLOCKS }
template={ TEMPLATE }
orientation="vertical"
renderAppender={ () => (
<InnerBlocks.ButtonBlockAppender />
) }
/>
</div>
)
},
save: (props) => {
return (
<div { ...useBlockProps.save({ style: STYLES }) }>
<div>
<InnerBlocks.Content />
</div>
</div>
)
},
} );
The renderAppender cb function could also return a custom element instead of the “ButtonBlockAppender” or “DefaultBlockAppender” components.
Pass down props
Props can also be passed down to the child of an InnerBlock using the providesContext and usesContext attributes. The child components inside the block can then use the attribute context from props and refer to the parent attribute that is passed down. Here’s an example:
import { registerBlockType } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import { TextControl } from '@wordpress/components';
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
//styles that make it look good in the editor
import './editor.scss';
const BLOCKNAME = "inner-blocks-passing-props";
const BLOCKPATH = `wp-gb/${BLOCKNAME}`;
registerBlockType( BLOCKPATH, {
apiVersion: 2,
title: __( 'Inner Blocks (passing props)', 'wp-gb' ),
description: __( 'The description' ),
category: 'wp-gb',
icon: 'smiley',
attributes: {
blockTitle: {
type: "string",
default: __( 'Parent Title (given here)', 'wp-gb' ),
}
},
providesContext: {
'parentTitle': 'blockTitle',
},
edit: ({attributes, setAttributes}) => {
const TEMPLATE = [ [ 'wp-gb/child-block', {} ] ];
return (
<div { ...useBlockProps() }>
<h1>Block title:</h1>
<TextControl
value={attributes.blockTitle}
onChange={(newValue) => {
setAttributes({blockTitle: newValue})
}}
/>
<InnerBlocks template={ TEMPLATE } />
</div>
)
}
} );
registerBlockType( "wp-gb/child-block", {
apiVersion: 2,
title: __( 'Child Block', 'wp-gb' ),
description: __( 'The description' ),
category: 'wp-gb',
icon: 'smiley',
usesContext: [ 'parentTitle' ],
edit: ({context}) => {
return (
<div { ...useBlockProps() }>
<h2>{context['parentTitle']}</h2>
</div>
)
}
} );
The save function can’t use the context attribute, so the chosen context needs to be stored as an attribute to be used in the save function.
useInnerBlocksProps
Inner blocks can also use something similar to the useBlockProps function where the wrapper element can be controlled. This function is experimental and is called useInnerBlocksProps. Here’s an example:
import { registerBlockType } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import { useBlockProps, InnerBlocks, __experimentalUseInnerBlocksProps as useInnerBlocksProps } from '@wordpress/block-editor';
//styles that make it look good in the editor
import './editor.scss';
const BLOCKNAME = "inner-blocks-with-inner-block-props";
const BLOCKPATH = `wp-gb/${BLOCKNAME}`;
const STYLES = {
minHeight: 100,
padding: "48px 48px 0 48px",
color: "black"
};
registerBlockType( BLOCKPATH, {
apiVersion: 2,
title: __( 'Inner Blocks With Inner Block Props', 'wp-gb' ),
description: __( 'The description' ),
category: 'wp-gb',
icon: 'smiley',
edit: (props) => {
const ALLOWED_BLOCKS = [
'core/paragraph',
'core/image',
];
const TEMPLATE = [ [ 'core/paragraph', {
placeholder: 'Enter side content...'
} ], [ 'core/image', {} ] ];
const blockProps = useBlockProps({ style: STYLES });
const innerBlockProps = useInnerBlocksProps( {
ref: blockProps.ref,
className: "unique-class"
}, {
allowedBlocks: ALLOWED_BLOCKS,
template: TEMPLATE,
});
return (
<div { ...blockProps }>
<div { ...innerBlockProps }>
{ innerBlockProps.children }
</div>
</div>
)
},
save: (props) => {
return (
<div { ...useBlockProps.save({ style: STYLES }) }>
<div className="unique-class">
<InnerBlocks.Content />
</div>
</div>
)
},
} );