Master InnerBlocks in Gutenberg. Learn how to nest blocks, restrict child types, and enforce templates to build complex layouts for your WordPress plugin.
Previously in this course, we covered the foundational aspects of Block API v2 Essentials: Metadata, React Edits, and SSR and how to manage global state using State Management with @wordpress/data: Building Scalable Stores. Building on that knowledge, this lesson focuses on creating complex, hierarchical layouts using InnerBlocks.
For our Knowledge Base plugin, we need a "Documentation Section" block that acts as a container for specific instructional components. Simple blocks aren't enough; we need a nested structure that enforces consistency.
In Gutenberg, InnerBlocks is a specialized React component that allows a block to contain other blocks. Think of it as a "drop zone" within your component. When you use InnerBlocks, you aren't just creating a wrapper; you are defining a recursive architecture where the parent block manages the layout, and the children manage the content.
The primary power of InnerBlocks lies in two areas:
We want to build a <kb-section> block that always contains a header and a list of step-by-step instructions. We will restrict the contents so users can only add our custom kb-step blocks or standard paragraph blocks.
In your block.json, you must set supports to allow nesting:
JSON{ "name": "kb/section", "title": "Knowledge Base Section", "category": "kb-blocks", "supports": { "innerBlocks": true } }
In your edit.js, import InnerBlocks from @wordpress/block-editor. We will define a TEMPLATE constant to pre-populate the container.
JAVASCRIPTimport { InnerBlocks, useBlockProps } from CE9178">'@wordpress/block-editor'; const TEMPLATE = [ [CE9178">'core/heading', { level: 3, placeholder: CE9178">'Section Title...' }], [CE9178">'kb/step', { placeholder: CE9178">'Enter step detail...' }] ]; const ALLOWED_BLOCKS = [CE9178">'core/heading', CE9178">'core/paragraph', CE9178">'kb/step']; export default function Edit() { const blockProps = useBlockProps(); return ( <div {...blockProps}> <InnerBlocks allowedBlocks={ALLOWED_BLOCKS} template={TEMPLATE} templateLock={false} /> </div> ); }
The save function is straightforward. It must output the <InnerBlocks.Content /> component to ensure the nested blocks are rendered correctly in the frontend.
JAVASCRIPTimport { InnerBlocks, useBlockProps } from CE9178">'@wordpress/block-editor'; export default function Save() { const blockProps = useBlockProps.save(); return ( <div {...blockProps}> <InnerBlocks.Content /> </div> ); }
In the example above, templateLock is set to false, allowing users to add or remove blocks. If you are building a rigid UI component, you can use:
'all': Users cannot move, remove, or insert new blocks.'insert': Users can move or delete blocks, but cannot insert new ones.In your current Knowledge Base plugin project, refactor your main "Documentation" block to use InnerBlocks.
TEMPLATE that includes a core/columns block to force a side-by-side layout for large screens.allowedBlocks to only permit core/paragraph and core/image inside those columns.<!-- wp:innerblocks --> comments.InnerBlocks.Content in Save: If you omit this in the save function, the nested blocks will exist in the database but will not render on the frontend.templateLock to 'all' too aggressively can frustrate users. Use it only when the block structure is strictly functional (e.g., a tabbed interface).allowedBlocks references a custom block, ensure that the custom block is registered before the parent block, otherwise the editor will fail to render the inner blocks correctly.We’ve moved from simple block registration to complex, nested architectures. By utilizing InnerBlocks, allowedBlocks, and template definitions, you ensure that your Knowledge Base plugin provides a structured, predictable authoring experience while maintaining the flexibility of the Gutenberg editor. These nested structures are the backbone of professional-grade WordPress page builders and specialized plugin UIs.
Up next: We will connect our nested blocks to the database by implementing Custom REST API Integration to fetch and save live Knowledge Base data.
Learn to persist Gutenberg state using Redux middleware. We’ll show you how to sync editor data to localStorage for a seamless, high-performance experience.
Read moreMaster Gutenberg block evolution. Learn to implement block transforms and deprecation handlers to ensure seamless backward compatibility for your plugin.
InnerBlocks and Nested Structures
Custom Hooks for React