Add Controls to a Gutenberg Custom Block

I am continuing my work with Gutenberg custom blocks and attributes/setAttributes. Previously I created a block with an attribute that was dispatched to InnerBlocks, but more commonly, I’ve needed to add some setting to the block itself.

Add attribute to block.json

The first step is to define the block attribute in block.json. Each attribute defined is included in the attributes prop on the block. The attribute must have a type (unless you use an enum) and can optionally have a default value and/or a source. If a source is provided, the attribute will be parsed from the block markup. Otherwise, it’ll be stored in the HTML comment for the block.

"attributes": {
  "title": {
    "type": "string",
    "default": "Back to Top"      
  }
}

Thus far, all the attributes I’ve worked with have been stored as HTML comments rather than using source to parse.

Add the UI to edit the attribute

Most often, I’ve wanted to either edit the attribute in the side panel or add editable text to the block.

For the first case, I use InspectorControls, PanelBody, and TextControl. InspectorControls adds controls to the settings sidebar. PanelBody is a WordPress component for a collapsible container. TextControl is a component for entering and editing plain text.

import { InspectorControls } from '@wordpress/block-editor';
import { PanelBody, TextControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';

function Edit() {
  return (
    <>
      <InspectorControls>
        <PanelBody title={__( 'My Custom Settings' )}>
          <TextControl
            label={__('Title')}
          />
        </PanelBody>
      </InspectorControls>
    </>
  );
}

For the second case, I use RichText within the block itself, which provides editable text that can include markup and can be styled so that it matches the front-end.

<RichText
  className='custom-block-heading'
  identifier='title'
  aria-label={__('Title')}
  placeholder={__('Title')}
  tagName='h3'
/>

Set the control value to the attribute value

attributes is one of the props passed to both the edit and save functions. The attributes object includes all attributes defined in block.json.

function Edit({ attributes }) {
  const {title} = attributes;
  ...
  <TextControl
    label={ __('Title') }
    value={ title }
  />
  ...
}

Update the attribute on change

setAttributes allows us to update the value of one or more attributes by passing it an object whose keys are the attribute(s) to update and whose values are the new attribute value(s). This can be called from the onChange event handler for a control.

function Edit({ attributes, setAttributes }) {
  ...
  <TextControl
    label={ __('Title') }
    value={ title }
    onChange={ (newTitle) => setAttributes({ title: newTitle }) }
  />
  ...
}

Use the attribute in the Save function

Thus far, I’ve been working in the Edit function. But when handling saving the block, attributes are once again passed as a prop and can be used the same way.

function Save({ attributes }) {
  const { title } = attributes;
  return <div>{ title }</div>
}

With that, the value of the title control will be rendered on the front-end (or used however you need it in your block).

One thing to note is that according to the WordPress documentation, when working with RichText, you should not simply render the attribute but use it as the value of a RichText.Content component to ensure HTML tags within the rich text render appropriately.

<RichText.Content
  className='custom-block-heading'
  value={ title }
  tagName='h3'
/>
References