Volto is the React-based frontend for Plone and will be the default frontend from Plone 6 forward. It’s highly customizable and allows content editors to assemble pages using Blocks. Specifically, this editor allows users to add, modify, reorder and delete Blocks.
Volto ships with a default set of Blocks, but did you know that you can also customize existing or create new Blocks? Here’s how I setup a custom Block from scratch using Volto (version 13.1.2).
Each Block contains two primary components:
View.jsx
Edit.jsx
To get started, create these two files in src/components/Blocks/MyCustomBlock/
:
View.jsx
import React from 'react';
const View = props => {
return <div>I'm the Block view component!</div>;
};
export default View;
Edit.jsx
import React from 'react';
const Edit = props => {
return <div>I'm the Block edit component!</div>;
};
export default Edit;
Next, let’s make the Block available by registering it in the blocksConfig
configuration object.
There are several ways to organize your files, but I prefer to create a separate customBlocks.js
file in src/components/Blocks
. This provides one central location to store all of our custom Blocks. I then import the view and edit components for MyCustomBlock and define the Block using the myCustomBlock
object below:
import MyCustomBlockView from '@package/components/Blocks/MyCustomBlock/View';
import MyCustomBlockEdit from '@package/components/Blocks/MyCustomBlock/Edit';
import icon from '@plone/volto/icons/list-bullet.svg';
const customBlocks = {
myCustomBlock: {
id: 'myCustomBlock',
title: 'My Custom Block',
edit: MyCustomBlockEdit,
view: MyCustomBlockView,
icon: icon,
group: 'text',
restricted: false,
mostUsed: false,
sidebarTab: 1,
security: {
addPermission: [],
view: [],
},
},
}
export default customBlocks;
In src/config.js
, we import customBlocks.js
and add it to the blocksConfig
.
We can use a spread operator to import the original settings config.block.blocksConfig
and then merge it with our new custom Blocks config ...customBlocks
.
Note: You could also add customBlocks
directly to src/config.js
, but having a separate file is cleaner.
import customBlocks from '@package/components/Blocks/customBlocks'
[...]
export default function applyConfig(config) {
config.blocks = {
...config.blocks,
blocksConfig: {
...config.blocks.blocksConfig,
...customBlocks},
}
return config;
}
Now, we have a working Block.
Note: It’s important to merge the new custom Block config into the existing blocks config. If you forget this step, the default Blocks will break displaying “Unknown block <id>” instead of content.
To use Blocks on your content types, you need to enable the Blocks
behavior through the Plone site using the following steps:
Site Setup > Dexterity Content Types
and then select your content type.Behaviors
tab.Blocks
behavior.This can also be done programmatically via GenericSetup:
<?xml version="1.0" encoding="utf-8"?>
<object name="custom_content_type" meta_type="Dexterity FTI"
i18n:domain="plone" xmlns:i18n="http://xml.zope.org/namespaces/i18n">
<property name="behaviors">
<element value="volto.blocks"/>
</property>
</object>
We’ve set up the basic structure for our Block, made Volto aware of it and made it available on the content type. Now you can build out the Edit component functionality or enhance your Block with Extensions.
src/omlette/components/Blocks
to see how the default Blocks are constructed.