Content Style Editor
The Style Editor is a UVE feature that lets authors select dynamic style properties on individual contentlets. A schema — defined per Content Type — determines which choices appear. The author's selections are stored on the contentlet and made available to both VTL templates and headless applications.
The Style Editor works for both traditional (VTL) pages and headless pages served by an external front end.
The quickest way to access the style properties for a given contentlet is through the UVE. Hitting the style button that appears over content summons the style editor pane on the right-hand side.
Configuring a Schema#
The style choices available to authors are defined by the Style Editor schema attached to a Content Type. Each Content Type has its own independent schema.
- Open the Content Types portlet.
- Open the Content Type you want to configure.
- Select the Style Editor tab.
From this tab you can add, edit, reorder, and remove sections and fields. Changes take effect immediately for any page that contains that Content Type.
The form has a number of tooltips that clarify the purposes of different elements.
Sections#
Sections are visual groupings — titled blocks in the Style Editor pane that keep related fields organized (for example, "Typography" and "Layout"). Sections appear only in the editor UI; they are not stored with the contentlet's data. Only field identifiers and their values are persisted.
A schema can have any number of sections. Each section must have a name and contains one or more fields.
Fields#
Each field represents one configurable style property. Every field has:
- Label — the text the author sees in the editor.
- Identifier — the variable name used in code to read the stored value. Must be unique within the Content Type. Identifiers containing hyphens or other non-alphanumeric characters require bracket syntax when accessed in VTL (see Using values in VTL).
There are four field types.
Text#
A free-text or numeric entry field. The stored value is a string or number matching the input kind.
Takes a label, and a description that displays as placeholder text.
Dropdown#
A single-select dropdown list.
Each option has a label (displayed to the author) and a value (the string persisted on the contentlet).
The stored value is the selected option's value string.
Radio#
A single-choice set of radio buttons, optionally displayed in a grid.
Each option has a label and a value (string). An optional image URL per option displays a visual preview (e.g., a layout thumbnail).
The stored value is the selected option's value string.
Radio buttons also have a Columns selector, to choose between rendering 1 or 2 columns in the editor pane.
Checkbox Group#
Multiple independent checkboxes; the author may select any combination.
Each option has a label and a key — the identifier for that checkbox in the stored object.
The stored value is an object mapping each option's key to true (checked) or false (unchecked):
{ "bold": true, "italic": false, "underline": true }
Stored Values#
When an author saves Style Editor selections, the values are stored on the contentlet as a flat object under dotStyleProperties. Sections are not represented — only field identifiers and their values appear.
Example — a schema with a Typography section (fontSize dropdown) and a Layout section (orientation radio):
{ "fontSize": "XL", "orientation": "Center" }
Fields for which the author has not yet made a selection do not appear in the object.
Using Values in VTL#
Style values are accessible in Velocity templates through the $dotContentMap global object:
$dotContentMap.dotStyleProperties.fontSize $dotContentMap.dotStyleProperties.orientation
If an identifier contains hyphens or other characters that are not valid Velocity property names, use map access:
$dotContentMap.dotStyleProperties['title-size']
For more on $dotContentMap, see Built-in Content Objects.
The Simplest Traditional Example#
You can see the Content Style Editor update in real time by simply adding the property to the VTL.
This quick and dirty addition will simply render the raw property set at the top of the page.
From here, you can see how making selections or adding inputs will adjust the property values in real time.
Such properties can activate any sort of behavior at the template level, limited only by one's time and imagination.
Avoid Global Variable Assignments#
VTL does not have template-scoped variables. A variable set inside a component template — whether in a loop, a container, or a shared #dotParse include — is visible across the entire request. Assigning a Style Editor value to a named variable and then reusing that variable across multiple contentlets of the same type is a common source of style bleed-through bugs.
Don't do this:
## $fontSize is overwritten for each contentlet rendered; later references may show the wrong value #set($fontSize = $dotContentMap.dotStyleProperties.fontSize)
Do this instead — reference the property inline wherever you need it:
#if($dotContentMap.dotStyleProperties.fontSize == "XL") ... #end
This ensures each evaluation is bound to the correct $dotContentMap context.
Using Values in Headless Applications#
On each contentlet returned by the Page API or Content API, saved Style Editor values are exposed as the dotStyleProperties property:
"dotStyleProperties": { "fontSize": "XL", "orientation": "Center" }
The dotCMS SDK types include dotStyleProperties, so it can be accessed and typed like any other contentlet field. For schema registration and advanced SDK integration, see SDK UVE Library.
Behavior: Traditional vs. Headless Pages#
The Style Editor works in both contexts, but the save mechanism differs.
| Page type | When a style change is saved |
|---|---|
| Headless | The change is applied immediately in the editor via postMessage (optimistic update). A backend save is triggered after a brief pause. If the save fails, the change is rolled back. |
| Traditional | A backend save is attempted immediately. If the save succeeds, the editor iframe reloads to display the updated page. If the save fails, the iframe is not reloaded and an error notification is shown. |
Real-time visual feedback is available on headless pages. On traditional pages, each saved change produces a brief page reload in the editor; neither requires an active refresh on the user side.