Editable Gutenberg Block

In this tutorial we are going to continue to work with the “subscription form” block we created in the previous tutorial.

It was completely static if you remember, but for now we are going to make it editable just like that:

editable Gutenberg block in WordPress
You may also noticed that “Bold” and “Italic” controls are only available for heading.

Setting up the Attributes

Each field you want to make editable should have its own attribute, you can think of it like of a meta key and meta value of a block. Today we are configuring the attributes of blocks in block.json file. In the old times we were doing it primarily in registerBlockType() function and this way is still working but I highly recommend to use block.json instead.

"attributes": {
	"heading": {
		"type": "string",
		"source": "html",
		"selector": "h3",
		"default": "Like this post? Join my mailing list!"
	"buttonText": {
		"type": "string",
		"source": "text",
		"selector": "span",
		"default": "Subscribe"

I think it would be great to highlight a couple moment in JSON code above.

  • As you can see we have two attributes here – heading and buttonText (you can choose the names), it is just because we have two editable elements in our block (check the screenshot above).
  • For out simple block the attribute properties type, source, selector and default should be quite clear to understand. You can read more about them in Gutenberg official documentation.

RichText Component


Now we have to replace all the static HTML tags from the original edit() function with <RichText> component. So we are going to replace <h3> and <span> tags.

import { useBlockProps, RichText } from '@wordpress/block-editor';

export default function Edit( { attributes, setAttributes } ) {

	const blockProps = useBlockProps();

		<div {...blockProps}>
				value={ attributes.heading }
				allowedFormats={ [ 'core/bold', 'core/italic' ] }
				onChange={ ( heading ) => setAttributes( { heading } ) }
				placeholder="Enter heading here..."
				<span>Email address</span>
					value={ attributes.buttonText }
					allowedFormats={ [] }
					onChange={ ( buttonText ) => setAttributes( { buttonText } ) }
					placeholder="Button text..."

Ok, let’s look at RichText component parameters I used. tagName and placeholder should be clear for you, but what about the other ones?

  • value – here we are going to provide the attribute value, if it doesn’t exist, the default value will be used which has been provided in block.json before.
  • allowedFormats – it allows you to define which formatting buttons are you going to use for this specific RichText component, accepts values core/bold, core/italic, core/link, core/strikethrough, core/code, core/image, core/underline, core/text-color, core/subscript, core/superscript, core/keyboard, by default all of them are available. If you want to deactivate everything, just pass an empty array [].
  • onChange – this parameter accepts a function name or an arrow function which you can see in my example. This function changes the component attribute on the fly which is its value in this case.


Nothing especial here, we’re just using RichText.Content to display the content of our RichText component.

import { useBlockProps, RichText } from '@wordpress/block-editor';

export default function Save( { attributes } ) {
	return (
		<div {...useBlockProps.save()}>
			<RichText.Content tagName="h3" value={ attributes.heading } />
				<input type="email" placeholder="Enter your email address" />
				<RichText.Content tagName="button" value={ attributes.buttonText } />
Misha Rudrastyh

Misha Rudrastyh

Hey guys and welcome to my website. For more than 10 years I've been doing my best to share with you some superb WordPress guides and tips for free.

Need some developer help? Contact me

Follow me on X