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
- Update the “attributes” section of “block.json” file to create necessary fields (No more ACF dependency, yay!)
- Create your HTML structure on “component.js” file and style it via “style.scss”
- Update your editable area like on the examples in the project, with the fields you defined on “block.json”
Leave a Reply