How do we make a WordPress Gutenberg attribute a required attribute? Curious if a property or attribute parameter can be defined, either in block.json or Edit.js, to avoid writing custom logic for each attribute.
block.json:
"attributes": {
"blockSubTitle": {
"type": "string",
"default": "OVERVIEW"
},
"blockImage": {
"type": "string",
"default": null
},
"blockImageId": {
"type": "integer",
"default": null
},
"topPadding": {
"type": "boolean",
"default": false
}
}
Block attributes can be updated in the Edit() function by using WordPress Gutenberg controls like a TextControl for a string
or NumberControl for integer
and ToggleControl for boolean
values.
All of these controls render out standard HTML form inputs which accept the required
attribute. By adding your own CSS className
, you can gain greater styling control over the required inputs for user feedback.
Eg. TextControl
<TextControl
label="Sub Title"
help="Required"
...
className="is-required" // or your own class name
required // this makes the input required
/>
As there is no default style for *:required:invalid
in the Editor stylesheet, by adding your own error styles in editor.scss
, the User will know when the input is required or in error:
editor.scss
/* Add a red asterisk after label to indicate required field */
.is-required * label::after{
color:#cc1818;
content:" *"
}
*:required:invalid {
border-color:#cc1818;
&:focus{
border-color:#cc1818;
box-shadow:0 0 0 1px #cc1818;
}
}
Depending on the purpose of the required block attributes, indicating the field is required and providing a safe default value in block.json
may be enough. However, if the required attribute is critical (eg. could potentially break something), then dispatching error notices for invalid values and preventing the post content from saving is the next step. Below is a complete example for a TextControl:
edit.js
import { InspectorControls, useBlockProps } from '@wordpress/block-editor';
import { PanelBody, TextControl } from '@wordpress/components';
import { useDispatch } from '@wordpress/data';
import { store as noticesStore } from '@wordpress/notices';
import './editor.scss';
export default function Edit({ attributes, setAttributes }) {
const { blockSubTitle } = attributes;
const { createErrorNotice, removeNotice } = useDispatch(noticesStore);
const setSubTitle = (value) => {
/* String cannot be empty */
if (value.length == 0) {
/* Dispatch error notice */
createErrorNotice('Sub title is required', {
id: 'subtitle-required',
isDismissible: false,
});
/* Prevent post content from saving and autosaving */
wp.data.dispatch('core/editor').lockPostSaving('subtitle-required');
wp.data.dispatch('core/editor').lockPostAutosaving('subtitle-required');
} else {
/* Save valid value */
setAttributes({ blockSubTitle: value });
/* Remove notice */
removeNotice('subtitle-required');
/* Unlock post */
wp.data.dispatch('core/editor').unlockPostSaving('subtitle-required');
wp.data.dispatch('core/editor').unlockPostAutosaving('subtitle-required');
}
}
return (
<div {...useBlockProps()}>
<InspectorControls>
<PanelBody>
<TextControl
label="Sub Title"
help="Required"
value={blockSubTitle}
onChange={(value) => setSubTitle(value)}
className="is-required"
required
/>
</PanelBody>
</InspectorControls>
<h2>{blockSubTitle}</h2>
</div>
);
}
The example edit.js
combined with editor.scss
when no value is given, renders: