How to add a metabox in React to Gutenberg
Recently I found myself in the need to add controls to the WordPress block editor, or Gutenberg as the project is also called, this is usually very simple but had a couple of complexities that I had not seen before:
- I needed to have controls in React and
- It needed to be positioned at the bottom of the editor
These requirements by themselves are not a major problem, but together it was something that is not usually done.
The problem
The issue here is that it is easy to do both separately, we can add a new plugin to the editor and show it on the sidebar, or, we can add a metabox with PHP and it will automatically show at the bottom of the editor.
Do you see the problem? There is no way to add a Gutenberg plugin at the bottom, and we cannot add React controls in PHP.
…Or can we?
The solution
It turns out that the solution is much simpler than I thought, what we need is a combination of both to make this work, basically, we can do the following:
- Create a metabox that appears at the bottom of the page, this only shows a container
- We create a Gutenberg plugin with the react functionality we need, this will be shown in the sidebar by default
- We create a portal that moves our React component to our container within the metabox
That's the magic! Now let's see how we can do it with code.
What is a Portal
?
This deserves its own post, but in a nutshell portals allow us to move parts of our components to any site within the DOM, but keep their structure within our React application.
Register a Metabox in WordPress
Now, if we want to do it with code, the first thing we need to do is create a Plugin that adds our metabox:
1<?php23/**4 * Plugin Name: Mah React metabox5 * Author: Mario Aguiar6 * Author URI: https://www.marioaguiar.net7 * Plugin URI: https://www.marioaguiar.net8 * Version: 1.09 */1011namespace Mah;1213/**14 * Handles metabox functionalities15 */16class Metabox17{18 /**19 * Adds the necessary hooks20 *21 * @return void22 */23 public function init(): void24 {25 add_action('add_meta_boxes', [$this, 'register_metabox']);26 }2728 /**29 * Adds a metabox30 *31 * @return void32 */33 public function register_metabox(): void34 {35 add_meta_box(36 'mah-metabox',37 __('Mah metabox'),38 function () {39 echo "<div id='mah-metabox-content'></div>";40 },41 null,42 'normal',43 'high'44 );45 }46}4748(new Metabox())->init();49
What this will do is add a new metabox to the block editor, if we don't look closely, we can guess that it is empty (although it simply doesn't have text), something like this:

Register a Plugin in Gutenberg
This will serve as the container for our React component, now, for our component we can add a new file, simply create a Gutenberg plugin using registerPlugin:
1/**2 * WordPress dependencies3 */4import { registerPlugin } from '@wordpress/plugins';5import { PluginDocumentSettingPanel } from '@wordpress/editor';67registerPlugin( 'mah-metabox', {8 render: () => {9 return (10 <PluginDocumentSettingPanel11 name="mah-metabox"12 title="Mah Metabox"13 >14 <h2>Mah Metabox</h2>15 </PluginDocumentSettingPanel>16 );17 },18} );19
Now we need to add our file to the editor:
1/**2 * Adds the necessary hooks3 *4 * @return void5 */6public function init(): void7{8 // …9 add_action('enqueue_block_editor_assets', [$this, 'enqueue_assets']);10}11
1/**2* Include scripts and dependencies in our plugin3 *4 * @return void5 */67public function enqueue_assets(): void8{9 $asset_file = include plugin_dir_path(__FILE__) . 'build/index.asset.php';1011 wp_enqueue_script(12 'mah-metabox',13 plugin_dir_url(__FILE__) . 'build/index.js',14 $asset_file['dependencies'],15 $asset_file['version'],16 true17 );18}19
And the result would be something like this:

Now we have the two components we need, and we are ready to put them together.
What is PluginDocumentSettingPanel
?
This is a Gutenberg component that allows us to add controls to the block editor, in this case we are using it to show our component in the sidebar.
Contrary to what this might make us think (and how simple it would be to do all this), there is no alternative that allows us to show our component at the bottom of the editor.
Joining the Gutenberg plugin with our Metabox
Fortunately, this is incredibly simple thanks to the aforementioned createPortal
,
we just need to modify our plugin to create a portal and send our component through that portal:
1/**2 * WordPress dependencies3 */4import { createPortal } from '@wordpress/element';5import { registerPlugin } from '@wordpress/plugins';67const Metabox = () => <h2>Mah Metabox</h2>;89const MetaboxPortal = () =>10 createPortal(<Metabox />, document.querySelector('#mah-metabox-content'));1112registerPlugin('mah-metabox', {13 render: MetaboxPortal,14});15
Done! That's all we need, what we are doing is creating a portal to our element with id mah-metabox
,
so, when React runs MetaboxPortal
it will know that it has to send its content through the portal,
and it will end up showing our component right where we need it, which is our metabox:

Conclusion
This is quite useful when we need more space than our sidebar can give us, a good example is the plugin Yoast SEO that shows the post information below the editor, which makes editing it much easier.
Once all these steps have been followed, we only need to add our controls as if we were working on any other
React project, and that's it, we already have a metabox in React in Gutenberg. With the advantage of being
able to access the post data and modify it directly from our component through the components in @wordpress/data
.
