Create a Volto theme add-on#
This chapter describes how to create a Volto theme add-on, helping you choose an appropriate method. It also covers tips and advanced topics for structuring your theme add-ons.
Choose an approach#
Volto supports two practical approaches to theme a site:
Use your project's default add-on as the theme. This option is practical when you want to have a single combined add-on for the exclusive use of your project and not reuse it for other projects.
Create a reusable theme add-on. This option is practical when you want to reuse your theme add-on for multiple projects.
Both approaches use the same mechanics under the hood. Pick the option that better fits your needs, then follow its corresponding documentation below.
The file volto.config.js
provides the ability to programmatically declare add-ons and the active theme.
See Programmatically define the active add-ons and theme for more information.
For convenience, it can also be set via a THEME
environment variable.
Use your project's default add-on as the theme#
This approach is simplest for a single project.
Ensure your default add-on is listed in
addons
, either involto.config.js
orpackage.json
.Set
theme
to your default add-on's package name, as described in Select the active theme.In your default add-on, create a file
src/theme/theme.config
, and set up the theme, as shown in the example in Select the active theme. Place any overrides undersrc/theme
.
Create a reusable theme add-on#
This approach is best when you want to reuse the same theme across multiple projects.
Create a Volto add-on package to host your theme, for example,
volto-my-theme
.Ensure your theme add-on is listed in
addons
(involto.config.js
orpackage.json
).In that add-on, create a directory
src/theme
and atheme.config
file as shown below.Declare the theme add-on in your project's
addons
, and settheme
to the theme add-on's package name.
Select the active theme#
For both of the foregoing methods to create a Volto theme add-on, you'll next need to declare the active theme.
You can declare the active theme in either of the two following ways, the first of which is preferred. The value you provide for your theme must be the package name of the add-on that contains the theme.
In the file
volto.config.js
at the project root.module.exports = { addons: [], theme: 'volto-my-theme' };
Use the
THEME
environment variable when starting Volto.THEME='volto-my-theme' pnpm start
Tip
If you use your project's default add-on as the theme, set theme
to your default add-on's package name.
Semantic UI entry point#
Again, for both approaches, you should create the entry point files for your theme under src/theme
.
src/
└── theme/
└── extras/
└── custom.overrides
└── custom.less
Contents of src/theme/extras/custom.overrides
:
@import 'custom.less';
/* No declarations beyond this point
place all your CSS in `custom.less` */
Contents of src/theme/extras/custom.less
:
// Place your theme customizations CSS here
Example theme.config
#
Create src/theme/theme.config
in the add-on that hosts the theme.
Replace <name_of_your_theme>
with the add-on package name.
/*******************************
Theme Selection
*******************************/
/* To override a theme for an individual element specify theme name below */
/* Global */
@site : 'pastanaga';
@reset : 'pastanaga';
/* Elements */
@button : 'pastanaga';
@container : 'pastanaga';
@divider : 'pastanaga';
@flag : 'pastanaga';
@header : 'pastanaga';
@icon : 'pastanaga';
@image : 'pastanaga';
@input : 'pastanaga';
@label : 'pastanaga';
@list : 'pastanaga';
@loader : 'pastanaga';
@placeholder : 'pastanaga';
@rail : 'pastanaga';
@reveal : 'pastanaga';
@segment : 'pastanaga';
@step : 'pastanaga';
/* Collections */
@breadcrumb : 'pastanaga';
@form : 'pastanaga';
@grid : 'pastanaga';
@menu : 'pastanaga';
@message : 'pastanaga';
@table : 'pastanaga';
/* Modules */
@accordion : 'pastanaga';
@checkbox : 'pastanaga';
@dimmer : 'pastanaga';
@dropdown : 'pastanaga';
@embed : 'pastanaga';
@modal : 'pastanaga';
@nag : 'pastanaga';
@popup : 'pastanaga';
@progress : 'pastanaga';
@rating : 'pastanaga';
@search : 'pastanaga';
@shape : 'pastanaga';
@sidebar : 'pastanaga';
@sticky : 'pastanaga';
@tab : 'pastanaga';
@transition : 'pastanaga';
/* Views */
@ad : 'pastanaga';
@card : 'pastanaga';
@comment : 'pastanaga';
@feed : 'pastanaga';
@item : 'pastanaga';
@statistic : 'pastanaga';
/* Extras */
@main : 'pastanaga';
@custom : 'pastanaga';
/*******************************
Folders
*******************************/
/* Path to theme packages */
@themesFolder : '~volto-themes';
/* Path to site override folder */
@siteFolder : "<name_of_your_theme>/theme";
/*******************************
Import Theme
*******************************/
@import (multiple) "~semantic-ui-less/theme.less";
@fontPath : "~volto-themes/@{theme}/assets/fonts";
.loadAddonOverrides() {
@import (optional) "@{siteFolder}/@{addon}/@{addontype}s/@{addonelement}.overrides";
}
/* End Config */
After starting Volto, the theme should be active.
Now you can add overrides to the default theme in src/theme
or directly with your custom CSS in src/theme/extras/custom.less
.
Using your own theming escape hatch#
Volto theming uses Semantic UI theming capabilities to define and extend a theme for your site.
However, while maintaining and playing well with the Semantic UI Volto base, you can use a traditional CSS approach using the LESS preprocessor-based extras
escape hatch.
At the same time, you can either discard or complement the extras
escape hatch and add your own, by customizing the theme.js
module in Volto.
Customizing the base theme is a special use case in Volto.
The original file is in Volto at volto/src/theme.js
.
This is the file to be customized.
In the customizations
folder, override it as customizations/volto/@root/theme.js
, using the @root
alias to avoid writing the full path.
Edit the imports in this file to align with the following code.
import 'semantic-ui-less/semantic.less';
import '@plone/volto/../theme/themes/pastanaga/extras/extras.less';
// You can add more entry points for theming
// This example assumes you want to use SCSS as preprocessor
// and your main.scss is in the `src/theme` folder
import '../../theme/main.scss';
You may want to do this to create a completely new theming experience adapted to your way of doing things that do not match the current Volto theming experience. For example, if you want to use another preprocessor in the theme, such as SCSS. Or perhaps your client requires the base consist entirely of pre-made components based on another library beside Semantic UI. See Using third party libraries and themes other than semantic-ui for an example of a custom theme escape hatch.
While building your own escape hatch for theming, you can use the preprocessor of your choice, while maintaining the "base" Volto theme, but customizing it using the resultant CSS. If you prefer a CSS variables-first approach for block styling, see the Block style wrapper guide, and use custom CSS properties to theme blocks consistently.
You can see an example of such a theme in Volto Light Theme.
Advanced: extend your theme in other add-ons#
Sometimes you have a custom theme that you want to reuse through all your projects, but with some differences, maintaining the base. Usually, the only option would be to use an add-on that adds more CSS to the base theme, using imports that will load after the theme. However, there is a problem with this approach. You cannot use existing theme variables, including breakpoints, on these new styles. Similarly, it gets somewhat detached from the normal flow of the loaded theme. The same applies for add-ons, as they are detached from the current theme. You could use a Semantic UI approach for making this work, but then it's bound to Semantic UI.
Warning
This is only possible when using your own escape hatch, and works only with SCSS-based themes, and not with Semantic UI themes, since it enables a couple of entry points that only support SCSS files. For an example of how it could be used, see Volto Light Theme.
If your custom escape hatch defines a custom theme using SCSS, you can take advantage of this feature. Although not limited to this, it would be possible to extend this feature to add more entry points, using another preprocessor or theming approach.
This feature enables two entry point files, _variables.scss
and _main.scss
.
From your add-on code, you can extend an existing theme by creating a file corresponding to each entry point:
./src/theme/_variables.scss
./src/theme/_main.scss
Variables#
You can use the entry point addonsThemeCustomizationsVariables
to modify the original variables of the currently loaded theme by adding the entry point before the theme variable definitions.
In the theme, it should be imported as shown below.
@import 'addonsThemeCustomizationsVariables';
@import 'variables';
@import 'typography';
@import 'utils';
@import 'layout';
Warning
Following SCSS best practices, your theme variables should be "overridable" using the !default
flag.
This assigns a value to a variable only if that variable isn't defined or its value is null
.
Otherwise, the existing value will be used.
Volto will not only load your add-on entry point files, but it will also detect all the add-ons that have these entry point files, and import them grouped under a single file.
It will also automatically add an addonsThemeCustomizationsVariables
alias that you can reference from the theme as shown above.
Main#
You can use the entry point addonsThemeCustomizationsMain
to add your own style definitions, complementing those in the theme.
You should add it after all the CSS of your theme:
@import 'blocks/search';
@import 'blocks/listing';
@import 'temp';
@import 'addonsThemeCustomizationsMain';
/* No CSS beyond this point */
Volto will also detect all the add-ons that have these entry point files, and import them grouped under a single file.
It will also automatically add an addonsThemeCustomizationsMain
alias that you can reference from the theme as shown above.
Note
These SCSS-based extension entry points work only when a theme is declared in either volto.config.js
or package.json
.
Which approach should I choose?#
Single project, fast iteration: use your default add-on as the theme.
Multiple projects, reuse required: create a separate theme add-on.
Prefer modern, cascade-friendly styling at block level: use CSS custom properties with the Block style wrapper.