Easy Native Gutenberg Block Development with a Single Component File

The Problem

Gutenberg block development best practices requires two different functions(edit & save) or files(edit.js & save.js) for both editor and frontend side of a block. That mostly makes us repeating ourselves on HTML part of block to make it similar on both sides.

Sample Native Card Block in Traditional Way

This is the normal way to create an editable sample “Card” block:

index.js:

import { registerBlockType } from '@wordpress/blocks';
import './style.scss';
import './editor.scss';
import Edit from './edit';
import save from './save';
import metadata from './block.json';

registerBlockType( metadata.name, {
   example: {
    attributes: {
      title: 'Preview Title',
      description: 'Preview description',
    },
  },
  edit: Edit,
  save,
} );Code language: JavaScript (javascript)

edit.js:

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

export default function Edit( { attributes, setAttributes } ) {
  const blockProps = useBlockProps();
  return (
    <div {...blockProps}>
      <RichText
        tagName="h2"
        value={attributes.title}
        allowedFormats={['core/bold', 'core/italic']}
        onChange={(val) => setAttributes({ title: val })}
        placeholder='Write a title'
      />

      <span className="description">
        <TextControl
          value={ attributes.description }
          onChange={ ( val ) => setAttributes( { description: val } ) }
          placeholder="Write a description"
        />
      </span>
    </div>
  );
}Code language: JavaScript (javascript)

save.js:

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

export default function save( { attributes } ) {
  const blockProps = useBlockProps.save();
  return (
    <div {...blockProps}>
      <RichText.Content tagName="h2" value={attributes.title} />

      <span className="description">
        {attributes.description}
      </span>
    </div>
  );
}Code language: JavaScript (javascript)

Think if your component requires more complex HTML in it. You would need to update both files to reflect changes on both admin and frontend sides.

Solution

Using only one component.js file instead of having both edit.js and save.js for basic HTML based editable components like Next, Nuxt, Astro, Svelte, etc components. You are only adding a small condition to editable part of a block. And, it will still be a Gutenberg-Native live edited block with ease.

Sample Native Card Block in Easier Way

Let’s create a “component.js” file and include into the “index.js” like this:

import { registerBlockType } from '@wordpress/blocks';
import metadata from './block.json';
import component from './component';

registerBlockType( metadata.name, {
  example: {
    attributes: {
      title: 'Preview Title',
      description: 'Preview description',
    },
  },
  edit: component,
  save: component
} );Code language: JavaScript (javascript)

component.js:

import { TextControl } from '@wordpress/components';
import { useBlockProps, RichText } from '@wordpress/block-editor';
import './style.scss';
import './editor.scss'; // Optional, in addition to style.scss only for editor side

export default function({ attributes, setAttributes }) {
  const editorScreen = typeof setAttributes !== "undefined";
  const blockProps = editorScreen ? useBlockProps() : useBlockProps.save();

  return (
    <div {...blockProps}>
      {editorScreen ?
        <RichText
          tagName="h2"
          value={attributes.title}
          allowedFormats={['core/bold', 'core/italic']}
          onChange={(val) => setAttributes({ title: val })}
          placeholder='Write a title'
        />
        :
        <RichText.Content tagName="h2" value={attributes.title} />
      }

      <span className="description">
        {editorScreen ?
          <TextControl
            value={ attributes.description }
            onChange={ ( val ) => setAttributes( { description: val } ) }
            placeholder="Write a description"
          />
          :
          attributes.description
        }
      </span>
    </div>
  );
}Code language: JavaScript (javascript)

All Working Starter Block Files

https://github.com/bilaltas/starter-block

How to create simple & custom blocks

  1. Update the “attributes” section of “block.json” file to create necessary fields (No more ACF dependency, yay!)
  2. Create your HTML structure on “component.js” file and style it via “style.scss”
  3. Update your editable area like on the examples in the project, with the fields you defined on “block.json”

Posted

in

,

by

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.