Skip to content

Upgrade Guide

This upgrade guide lists all breaking changes in Volto and explains the steps that are necessary to upgrade to the lastest version.


There are times that updating the Volto boilerplate (the one generated by @plone/create-volto-app) is enough to fulfill all the changes. If you haven't heavilly modified it, moving things around and copying over your dependencies might do when dealing with upgrades. We keep the generator up to date and in sync with current Volto release.

Upgrading to Volto 4.x

First, update your package.json to Volto 4.x.x.

  "dependencies": {
    "@plone/volto": "4.0.0",

Tiles engine - Tiles configuration object

The tiles engine was updated and there are some important breaking changes, in case that you've developed custom tiles. The configuration object is now unified and expresses all the properties to model a tile. This is how a tile in the defaultTiles object looks like:

const defaultTiles = {
  title: {
    id: 'title', // The name of the tile
    title: 'Title', // The display name of the tile
    icon: titleSVG, // The icon used
    group: 'text', // The group (tiles now can be grouped)
    view: ViewTitleTile, // The view mode component
    edit: EditTitleTile, // The edit mode component
    restricted: false, // If the tile is restricted, it won't show in menus
    mostUsed: false, // A meta group `most used`, appearing at the top
    tileHasOwnFocusManagement: false, // Set this to true if the tile manages its own focus
    security: {
      addPermission: [], // Future proof (not implemented yet) add permission role(s)
      view: [], // Future proof (not implemented yet) view role(s)

There is an additional object groupTilesOrder that contains an array with the order that the tiles group should appear:

const groupTilesOrder = [
  { id: 'mostUsed', title: 'Most used' },
  { id: 'text', title: 'Text' },
  { id: 'media', title: 'Media' },
  { id: 'common', title: 'Common' },

You should adapt and merge the configuration of your own custom tiles to match the defaultTiles and groupTilesOrder one. You can modify the order of the groups and create your own as well.

Tiles engine - Simplification of the edit tiles wrapper

The edit tile wrapper boilerplate was quite big, and for bootstrap an edit tile you had to copy it from an existing tile. Now all this boilerplate has been transferred to the Tiles Engine, so bootstrapping the edit component of a tile is easier and do not require any pre-existing code.

In order to upgrade your tiles you should simplify the outter <div> (took as example the Title tile):

--- a/src/components/manage/Tiles/Title/Edit.jsx
+++ b/src/components/manage/Tiles/Title/Edit.jsx
@@ -138,11 +138,7 @@ class Edit extends Component {
       return <div />;
     return (
-      <div
-        role="presentation"
-        onClick={() => this.props.onSelectTile(this.props.tile)}
-        className={cx('tile title', { selected: this.props.selected })}
-      >
+      <>
@@ -185,7 +181,7 @@ class Edit extends Component {
             this.node = node;
-      </div>
+      </>

The tiles engine now takes care for the keyboard navigation of the tiles, so you need to remove the outter <div> from your custom tile, then your tile doesn't have to react to the change on this.props.selected either, because it's also something that the tiles engine already does for you.

The focus management is also transferred to the engine, so no needed for your tile to manage the focus. However, if your tile does indeed require to manage its own focus, then you should mark it with the tileHasOwnFocusManagement property in the tiles configuration object:

    text: {
      id: 'text',
      title: 'Text',
      icon: textSVG,
      group: 'text',
      view: ViewTextTile,
      edit: EditTextTile,
      restricted: false,
      mostUsed: false,
      tileHasOwnFocusManagement: true,
      security: {
        addPermission: [],
        view: [],

Default view renaming

The default view for content types DocumentView.jsx has been renamed to a more appropiate DefaultView.jsx. This view contains the code for rendering blocks in case the content type has been Blocks enabled. Enable Blocks on your content types by composing the view of your content type using DefaultView component.


  • The old messages container has been removed since it's not used anymore by Volto. We changed it to use Toast library.
  • Improve the Pastanaga Editor block wrapper container layout, deprecating the hack .ui.wrapper > *.

Upgrading to Volto 3.x

Volto was upgraded to use Razzle 3.0.0 which is not a breaking change itself, but it forces to some changes in the boilerplate on your Volto projects. You should change the babel config by deleting .babelrc file and creating a new file babel.config.js with these contents:

module.exports = require('@plone/volto/babel');

Then update your package.json to Volto 3.x.

  "dependencies": {
    "@plone/volto": "3.0.0",

Volto 3.x is compatible with the new changes introduced in the vocabularies endpoint in plone.restapi 4.0.0. If you custom build a widget based in the Volto ones, you should update them as well. Volto updated its own widget set to support them:

  • components/manage/Widgets/ArrayWidget
  • components/manage/Widgets/SelectWidget
  • components/manage/Widgets/TokenWidget

They all use react-select third party library for render it.

Upgrading to Volto 2.x

Improved Tiles HOC

The Tiles HOC (High Order Component) was changed to lift off some of the features from the tiles themselves and now it takes care of them by its own.

  • The delete tile feature was moved to it
  • The keylisteners for navigating through tiles was moved to it
  • The properties passed down to the tiles are improved and documented

This change only applies to your existing tiles, you have to update them accordingly by delete the trash icon and action from the end of your tiles

{this.props.selected && (
    onClick={() => this.props.onDeleteTile(this.props.tile)}
    <Icon name={trashSVG} size="18px" />

Modify the parent element of your tile making this changes:

  onClick={() => this.props.onSelectTile(this.props.tile)}
  className={cx('tile hero', {
    selected: this.props.selected,
  onKeyDown={e =>
  ref={node => {
    this.node = node;
  • Add the keylisteners to the parent element of your tile
  onKeyDown={e =>
  • Add a ref to it and assign it to this.node.
  ref={node => {
    this.node = node;
  • Add a proper role for it

Take a look into the implementation of the default Volto tiles to get a grasp on all the edge cases related to keyboard navigation and how to deal with them.

Reordering of the internal CSS, added an extra

The internal Volto CSS has been tidied up and reordered, for that reason, some other extras have been introduced and the theme.config in your project needs to be updated by making sure you have these two extras in the theme.config file:

/* Extras */
@main        : 'pastanaga';
@custom      : 'pastanaga';