How to create a custom Gutenberg block toolbar control?

So, you’re diving into custom Gutenberg blocks and you’ve hit a point where you want to add a bit more flair, a touch more control, directly to your block’s toolbar. That familiar little row of icons that pops up when you select your block – yeah, that one! It’s a common next step for many, and thankfully, it’s more accessible than you might think.

The short answer? You create a custom Gutenberg block toolbar control by defining a new component that renders within the BlockControls slot. This involves understanding React components, Gutenberg’s data store, and a little bit about how WordPress renders these interface elements. It’s about extending the existing interface, not reinventing the wheel, and the tools are already there for you.

The Building Blocks: What You Need to Know

Before we get our hands dirty, let’s make sure we’re on the same page with a few key concepts. You don’t need to be a seasoned React ninja, but a basic understanding will smooth out the learning curve significantly.

Understanding Gutenberg’s Architecture

Gutenberg, now the default WordPress editor, is built using React. This means its interface, including blocks, toolbars, and inspector panels, is composed of React components. Each block registers its own set of components, and the editor orchestrates how they’re displayed.

  • InnerBlocks vs. Reusable Blocks: It’s worth noting the difference. InnerBlocks allows creating blocks that can contain other blocks, building complex nested structures. Reusable blocks are saved entities that can be inserted multiple times across posts. We’re focusing on custom toolbar controls for your own unique blocks.

React Fundamentals (A Quick Refresher)

If you’ve dipped your toes into React, you’ll be familiar with concepts like components, props, and state. For building custom controls, you’ll primarily be working with components.

  • Components: Think of these as the LEGO bricks of your user interface. You create a function or class that returns JSX (JavaScript XML), which describes what should be rendered.
  • Props: These are like arguments passed to components, allowing you to customize their behavior and appearance from their parent.
  • State: This refers to data that a component manages and can change over time. While less critical for simple toolbar controls, it becomes important if your control needs to maintain some sort of internal state.

Gutenberg’s Data Store

WordPress uses a Redux-like data store to manage the editor’s state. Block attributes, selected blocks, and other crucial information are stored here. You’ll interact with this store to read data and dispatch actions to update it.

  • useSelect and useDispatch Hooks: These are your primary tools for interacting with the data store in modern Gutenberg development. useSelect lets you grab data, and useDispatch allows you to send commands.

If you’re looking to enhance your WordPress development skills, particularly in creating custom Gutenberg block toolbar controls, you might find it beneficial to explore related resources. One such article that provides valuable insights into payment integration for WordPress is available at this link. It offers a comprehensive guide on implementing payment solutions, which can complement your understanding of custom block development by showcasing how to integrate various functionalities within the WordPress ecosystem.

The Toolbar Blueprint: Where Your Control Lives

The block toolbar isn’t just some arbitrary space; it’s a deliberate part of Gutenberg’s UI structure. Understanding where your custom control fits in is crucial.

BlockControls and InspectorControls

When you’re developing a custom block, you’ll often come across two key components for adding UI elements: BlockControls and InspectorControls.

  • BlockControls: This is where the magic for the block toolbar happens. Anything rendered within the BlockControls component will appear in the floating toolbar that accompanies your block when it’s selected. This is the target for our custom controls.
  • InspectorControls: This component renders controls in the block settings sidebar (the panel that appears on the right when you click the gear icon). These are for more complex settings that don’t need to be in the immediate toolbar.

The Principle of SlotFills

Gutenberg employs a powerful pattern called “SlotFills.” This is how different parts of the editor can contribute UI elements to specific areas. BlockControls is a “slot,” and when you render a component within it, you’re essentially “filling” that slot.

  • The name Prop: When using BlockControls, you’ll often see a name prop. This helps WordPress identify and organize different types of controls within the toolbar. For custom controls, you’ll define your own specific areas.

Crafting Your Custom Control: The Code Walkthrough

Now, let’s get to the practical part. We’ll build a simple example to illustrate the process. Imagine we want to add a button to our block’s toolbar that toggles a highlight attribute for the block.

Step 1: Registering Your Block

This is the foundational step. Assuming you have a block.json file and a registration script, you’ll have a basic block set up.

“`javascript

// src/index.js or similar file where your block is registered

import { registerBlockType } from ‘@wordpress/blocks’;

import ‘./style.scss’; // For block styles

import ‘./editor.scss’; // For editor-specific styles

import Edit from ‘./edit’; // Your block’s edit component

import save from ‘./save’; // Your block’s save component

registerBlockType(‘my-plugin/my-custom-block’, {

edit: Edit,

save: save,

// … other block settings

});

“`

Step 2: Defining the Edit Component

This Edit component is where you’ll house your toolbar control. It receives block attributes, setAttributes, and className as props.

“`javascript

// src/edit.js

import { __ } from ‘@wordpress/i18n’;

import { useBlockProps, BlockControls } from ‘@wordpress/block-editor’;

import { ToolbarGroup, ToolbarButton, Tooltip } from ‘@wordpress/components’;

import { formatBold } from ‘@wordpress/icons’; // Example icon

function Edit({ attributes, setAttributes }) {

const blockProps = useBlockProps();

const { isHighlighted } = attributes; // Assuming you have a ‘isHighlighted’ attribute

const toggleHighlight = () => {

setAttributes({ isHighlighted: !isHighlighted });

};

return (

<>

icon={formatBold} // Use an available icon

label={__(‘Toggle Highlight’, ‘my-plugin’)}

onClick={toggleHighlight}

isActive={isHighlighted} // Highlight the button if active

/>

{/ Your block’s content goes here /}

This is my custom block.

{isHighlighted && Highlighted!}

);

}

export default Edit;

“`

Step 3: Adding Block Attributes

Your block.json needs to define the attribute that your toolbar control will manage.

“`json

// block.json

{

“apiVersion”: 2,

“name”: “my-plugin/my-custom-block”,

“version”: “0.1.0”,

“title”: “My Custom Block”,

“category”: “text”,

“attributes”: {

“isHighlighted”: {

“type”: “boolean”,

“default”: false

}

},

“editorScript”: “file:./index.asset.php”,

“editorStyle”: “file:./index.css”,

“style”: “file:./style-index.css”

}

“`

Step 4: Handling Styles (Editor and Frontend)

You’ll need styles to visually indicate the highlighted state.

“`scss

// src/editor.scss

.wp-block-my-plugin-my-custom-block.is-highlighted {

border: 2px solid yellow;

background-color: rgba(255, 255, 0, 0.2);

}

// src/style.scss (for frontend)

.wp-block-my-plugin-my-custom-block.is-highlighted {

border: 2px solid yellow;

background-color: rgba(255, 255, 0, 0.2);

}

“`

Deep Dive: The Components You’ll Use

The example above touches on several important components from @wordpress/components and @wordpress/block-editor. Let’s unpack them.

BlockControls

As mentioned, this is the wrapper. It tells Gutenberg, “Everything inside here belongs in the block toolbar.”

  • Structure: You’ll typically wrap your toolbar items within ToolbarGroup components for better organization. Blocks can have multiple ToolbarGroups to separate related controls.

ToolbarGroup

This component groups related toolbar items. It can help declutter the toolbar, especially if you have many controls.

  • Purpose: Think of it as a visual separator or a logical grouping. For complex blocks, you might have a group of text formatting tools and another group for layout options.

ToolbarButton

This is the star of your custom control. It renders an icon, a label (for tooltips and accessibility), and an onClick handler.

  • icon Prop: Accepts a React element, typically an SVG icon imported from @wordpress/icons (like formatBold, alignLeft, image, etc.). You can also create your own SVG icons.
  • label Prop: This is crucial for accessibility and for the tooltip that appears when a user hovers over the button. Use speak strings from @wordpress/i18n for translation.
  • onClick Prop: This is where you define the action that happens when the button is clicked. This is where you’ll use setAttributes to update your block’s state.
  • isActive Prop: A boolean that, when true, visually indicates that the button’s associated action is currently active (e.g., the bold button is active if the text is bold). This is perfect for toggling states.

Tooltip

Although not directly used in the ToolbarButton itself in this example, Tooltip is often used in conjunction with ToolbarButton to provide explanatory text when hovering. The label prop on ToolbarButton essentially handles this functionality for you.

If you’re looking to enhance your custom Gutenberg block by adding a toolbar control, you might find it helpful to explore related topics that can improve your overall site performance. For instance, optimizing your website’s speed can significantly impact user experience and SEO. A great resource for this is an article on Google PageSpeed Insights, which provides valuable insights on how to improve your site’s loading time. You can read more about it here. This knowledge can complement your efforts in creating a more efficient and user-friendly block editor experience.

Advanced Scenarios and Further Customization

Once you’ve got the basics down, you might want to explore more complex scenarios or refine your controls.

Multiple Controls in One Group

You can add as many ToolbarButton components as you need within a single ToolbarGroup.

  • Example: For a “style” control, you might have three ToolbarButtons: one for “primary,” one for “secondary,” and one for “outline” styles, each triggering a different setAttributes call.

Using Different Icons

The @wordpress/icons package is a treasure trove of common icons.

  • Importing: import { IconName } from '@wordpress/icons';
  • Custom SVGs: If you need a unique icon, you can create an SVG and render it as a React component. A common practice is to save it as a .js or .jsx file.

“`javascript

// src/components/MyCustomIcon.js

import React from ‘react’;

const MyCustomIcon = (props) => (

);

export default MyCustomIcon;

“`

Then, import and use it:

“`javascript

import MyCustomIcon from ‘./components/MyCustomIcon’;

// … inside your Edit component

} label={__(‘My Custom Action’, ‘my-plugin’)} />

“`

Conditional Rendering of Controls

You might want a toolbar button to only appear under certain conditions.

  • Based on Block State: If your block has different configurations, you can use prop checks to conditionally render buttons.
  • Based on Editor State: Using useSelect to check the globally selected block can also influence visibility, though this is less common for your block’s specific toolbar.

“`javascript

// Example: Show button only if another attribute is set

function Edit({ attributes, setAttributes }) {

const { someOtherSetting, isHighlighted } = attributes;

return (

<>

{someOtherSetting && ( // Conditional rendering

icon={formatBold}

label={__(‘Toggle Highlight’, ‘my-plugin’)}

onClick={() => setAttributes({ isHighlighted: !isHighlighted })}

isActive={isHighlighted}

/>

)}

{/ … rest of your block /}

);

}

“`

Interacting with Other Block Data

Sometimes, your toolbar control might need to read or modify attributes of other blocks. This is where useSelect and useDispatch come in handy.

  • Getting Block Info: const { getBlockAttributes } = useSelect('core/block-editor');
  • Updating Other Blocks: const { updateBlockAttributes } = useDispatch('core/block-editor');

This is more advanced and requires careful consideration of how your block interacts with the rest of the content. For simple controls on your own block, stick to setAttributes.

Best Practices for Toolbar Controls

To make your custom controls effective and user-friendly, keep these tips in mind:

Keep it Concise

The block toolbar has limited space. Aim for controls that perform discrete, useful actions. Avoid cluttering it with too many options.

  • Focus on Primary Actions: Think about the most frequent or important things users will do with your block.
  • Offload Complex Settings: If a control requires many options or is less frequently used, consider putting it in the InspectorControls sidebar.

Clear and Actionable Labels

The label prop is vital.

  • Be Descriptive: Instead of “Option 1,” use “Set Background Color” or “Align Left.”
  • Use __( 'Your Label', 'your-text-domain' ): Always internationalize your labels for translation.

Appropriate Icons

Choose icons that intuitively represent the action.

  • Standard Icons: Leverage common icons from @wordpress/icons when available.
  • Consistency: If you have similar actions, use similar icons.

State Indication (isActive)

For togglable features, the isActive prop on ToolbarButton is a must. It provides immediate visual feedback to the user.

  • Example: If a button toggles an outline, the button should look “pressed” or highlighted when the outline is active.

Performance Considerations

While generally not a major concern for simple toolbar controls, be mindful if your control involves complex logic or data fetching.

  • Avoid Expensive Operations: Don’t perform heavy calculations or network requests directly within the onClick handler if it can be avoided.
  • Memoization: If your control’s rendering or logic becomes complex, consider React’s useMemo and useCallback hooks.

Putting It All Together: A Checklist

Before you ship your custom block with its new toolbar control, run through this quick checklist:

  1. Block Registered: Is your block correctly registered in index.js?
  2. block.json Attributes: Is the necessary attribute defined with the correct type and default?
  3. Edit Component: Is the Edit component set up to receive props like attributes and setAttributes?
  4. BlockControls: Is your custom UI wrapped within BlockControls?
  5. ToolbarGroup & ToolbarButton: Are you using these components correctly?
  6. icon: Is an appropriate icon provided?
  7. label: Is the label clear, translatable, and descriptive?
  8. onClick: Does the onClick handler correctly call setAttributes to toggle or change the relevant attribute?
  9. isActive (if applicable): Is isActive used to reflect the current state of the control?
  10. Styling: Are editor and frontend styles applied to visually reflect the attribute change?
  11. Testing: Does the control work as expected in the editor? Does the change persist when the post is saved and reloaded?

Creating custom Gutenberg block toolbar controls is a fantastic way to enhance the user experience for your blocks. By understanding the underlying React structure, Gutenberg’s component system, and the role of BlockControls, you can add powerful and intuitive options directly into the editing workflow, making your custom blocks shine.