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
- https://developer.wordpress.org/block-editor/reference-guides/block-api/block-attributes/
- https://developer.wordpress.org/block-editor/reference-guides/components/panel/
- https://developer.wordpress.org/block-editor/reference-guides/components/text-control/
- https://developer.wordpress.org/block-editor/reference-guides/richtext