How to Create a Gutenberg Block if You Know Nothing

I want to begin with some kind of intro. Let’s suppose guys, that you have some experience with builders, like… (I do not want to call their names). Do you remember how all the builders work? With the help of shortcodes, right?

It is a shortcode in a shortcode in a shortcode in a shortcode! 😱

But what is a shortcode? It is PHP code, right? The first mistake with Gutenberg might be thinking that its blocks are something like shortcodes.

But it is not true, the result HTML is generated immediately while you edit your content with Gutenberg and saved in database just the same form it is going to be displayed on your website. Well, maybe excluding Gutenberg comments like this: <!-- wp:misha/newsletter -->

Below is what we are going to create in this tutorial – simple subscription form block.

How to create a Gutenberg block for Subscription form
Once created, the block can be used as many times in post content as you need.

Step 1. Enqueue Block JS and CSS

The simplest part of the tutorial because I think most of you are familiar with it.

Let’s begin with creating two files in your theme / plugin folder, one is block-newsletter.js and another is block-newsletter.css. I think it should be clear what we’re going to put in these files.

Once you created the files, we can try to include them:

add_action( 'enqueue_block_editor_assets', 'misha_block_assets' );
function misha_block_assets(){
		plugin_dir_url( __FILE__ ) . 'assets/block-newsletter.js',
		array( 'wp-blocks', 'wp-element' ),
		filemtime( dirname( __FILE__ ) . '/assets/block-newsletter.js' )
		plugin_dir_url( __FILE__ ) . 'assets/block-newsletter.css',
		array( 'wp-edit-blocks' ),
		filemtime( dirname( __FILE__ ) . '/assets/block-newsletter.css' )

I decided to work in a custom plugin which I’ve created specifically for this block, so I use plugin_dir_url( __FILE__ ) to get the URL of the plugin folder and filetime() function to prevent .js and .css files from being cached while I’m working with them.

To make sure that your files have been enqueued, you can insert some simple code there, like alert( 'test' ) in the block-newsletter.js file and body{ background: #000 } in block-newsletter.css file.

Note: Please use block-newsletter.css only to customize this certain block, do not use it if you need to change some Gutenberg editor styles, in case you need to, make a look at this tutorial.

Step 2. Using registerBlockType() to Create a New Gutenberg Block

Components Explained

In order to create a simple not editable block, we will need createElement() method, which is the part of wp.element component and registerBlockType() which is the part of wp.blocks component. Seems clear at this moment?

( function( blocks, element ) {
	const el = element.createElement;
	const { registerBlockType } = blocks; 
	// const registerBlockType = blocks.registerBlockType; // the same
	registerBlockType( .... ); // it is described in the next chapter
} )(
	window.wp.blocks, // wp.blocks becomes just "block" variable

In the above code I can also write:

	const { createElement } = element;
	const { registerBlockType } = blocks;

But while working with blocks usually we have to use createElement() too often and it will be much more easier if this method will be named el().


It is where all the magic happens when you create Gutenberg blocks.

registerBlockType( 'misha/newsletter', {
	title: 'Newsletter',
	icon: iconEmail,
	category: 'common',
	keywords: [ 'email', 'subscribe', 'misha' ],
	edit: function( props ) {
	save: function( props ){

misha/newsletter (line 7) – is the block ID, you can use something/something

iconEmail (line 9) is the constant / variable which contains a SVG icon, there is a separate tutorial about icons in Gutenberg, highly recommended to read.

category (line 10) – in which category your block should be:

Block categories in Gutenberg
So you can use one of the following – common, formatting, layout, widgets, embed.

keywords (line 11) – specify no more than 3 keywords in an array. When somebody performs a search for a block, the block title and keywords will be used.

edit() and save() functions are described below.


This function returns HTML code which is used to display a block in Gutenberg. And it is critical to understand.

It means that for our block we do need <form> or <button> tags, they will be in save() function below. But here we must use just static HTML elements like div or span or p. That’s all!

In the next tutorial we are going to replace some of them with Editable and RichText components, but at this moment our block is not editable, so we will leave it for now.

In order to understand the below code you have to learn some basics about creating elements in React.

edit: function( props ) {
	return (
		el( 'div', { className: props.className },
			el( 'div', { className: 'misha-block-form-wrap' },
				el( 'div', {},
					'Enter your email address'
				el( 'div', {},


This function should return HTML how the block is going to be displayed on the website pages and saved to database. That’s why here we’re using <form>, <input> and <button> tags.

save: function( props ) {
	return (
		el( 'div', { className: props.className },
			el( 'form', { className: 'misha-block-form-wrap' },
				el( 'input', { 'type': 'email', 'placeholder' : 'Enter your email address' } ),
				el( 'button', {}, 

Finally, the result.

Please note, that if you try to make any changes in “Edit as HTML” mode, your block will become broken. It is not editable, remember? I will explain more in details why in happens in the next tutorial.

We’re done 🎉

If you would like to download the ready plugin, here it is.

Read also

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 Twitter