Composition properties
Composition properties give a single Visual Builder experience several independent layouts, such as a main canvas and an aside. Content managers edit each layout separately.
A composition holds the layout of an experience or section. It stores the structure of the layout's nodes, the display templates applied to them, and the components they contain. Every experience and section content type has one built-in composition. Experience content types can also declare additional composition properties.
This topic describes how to configure compositions through the CMS (SaaS) REST API. It covers a composition's layout, the content types it can contain, and how to read and write its value. For the structure of the composition value itself, see Configure Visual Builder.
Prerequisites
Before you start, make sure you have the following:
- A REST API token – Create an API key in Settings > API Keys, and use it to request a token. See API keys and Authentication and authorization.
- The right scopes, if your token is restricted – Configuring compositions on a content type requires the contenttypes:admin scope. Writing composition values requires the content:admin scope.
Built-in and custom compositions
Compositions come in two kinds, and you configure each kind in a different place on the content type.
Aspect | Built-in composition | Custom composition property |
|---|---|---|
Base types | _experience and _section | _experience only |
Number per content type | Exactly one, always present | Any number, opt-in |
Configured through | The composition field on the content type | A property of type composition in the content type's properties |
Value read and written through | The composition field on the content version | properties.PROPERTY_KEY.value on the content version |
Editing surface | The main Visual Builder canvas | A separate canvas the content manager switches to |
Built-in and custom compositions use the same value shape: a tree of composition nodes. CMS (SaaS) indexes each one to Optimizely Graph as a CompositionStructureNode. Nothing in the value distinguishes one kind from the other.
Note Only experience content types support custom composition properties. A section content type can use only its built-in composition. A composition property also cannot be an item in an array property. The key composition is reserved for the built-in composition, so you cannot declare a property with that key.
Layout types
A composition's layout type determines which nodes it can contain.
- outline – A flat, ordered list of sections or section-enabled components. The default for experiences.
- grid – A hierarchical structure of rows, columns, and elements. The default for sections.
- form – The structure of a form: steps, rows, columns, and form elements. Available when you activate Optimizely Forms. See Activate forms.
Set the layout type with the format field on the content type's composition field or on a composition property. If you omit format, the composition uses the default layout type for the base type.
The layout type also decides the shape of the value:
- With outline, the root node holds a flat, ordered list of section nodes and section-enabled component nodes. A section node carries its own composition, which is where its rows, columns, and components live.
- With grid, the root node holds rows directly, and each row holds columns, which hold components.
Important You cannot change the format of a composition after content that uses it exists. Such a request fails with The layout type of 'PROPERTY_KEY' cannot be changed from 'CURRENT_LAYOUT_TYPE' to 'NEW_LAYOUT_TYPE' because the property already has content.
Add a custom composition property
Declare the property in the content type's properties with the data type composition. The following example creates an experience content type with two compositions. The built-in composition uses outline, and an extra sidebar composition uses grid.
POST https://api.cms.optimizely.com/v1/contenttypes
Content-Type: application/json{
"key": "landingPage",
"baseType": "_experience",
"displayName": "Landing page",
"composition": {
"format": "outline"
},
"properties": {
"sidebar": {
"type": "composition",
"format": "grid",
"displayName": "Sidebar",
"description": "A secondary canvas rendered beside the main content.",
"sortOrder": 10
}
}
}A GET of the content type returns the property in the same shape. The built-in composition is a system property, so it never appears under properties. The content type's composition field reports its settings instead. The response omits that field when the content type does not override the built-in composition.
Configure the built-in composition
Use the content type's composition field to configure the built-in composition. Use it to override the layout type and restrict which content types the composition can contain. It applies only to content types with base type _experience or _section.
The following request changes the built-in composition of landingPage to grid and limits it to heroBlock and element content types.
PATCH https://api.cms.optimizely.com/v1/contenttypes/landingPage
Content-Type: application/merge-patch+json{
"composition": {
"format": "grid",
"allowedTypes": [ "heroBlock", "_element" ]
}
}Set composition to null to remove the override and fall back to the default layout type for the base type.
Restrict the types a composition can contain
Restrict a composition's content types so content managers can add only the content types that belong in that layout. Built-in compositions and custom composition properties support allowedTypes and restrictedTypes. These are the same validation fields that content and contentReference properties use. See Validation fields.
- allowedTypes – Content types that the composition can contain. An empty or omitted array means no allow list.
- restrictedTypes – Content types that the composition must not contain. It takes priority over allowedTypes.
Each entry is a content type key or a base type, such as _component or _section. To allow every content type that fulfills a contract, list the contract.
The following example allows ctaElement and imageElement in the sidebar composition and restricts videoElement.
{
"key": "landingPage",
"baseType": "_experience",
"displayName": "Landing page",
"properties": {
"sidebar": {
"type": "composition",
"format": "grid",
"allowedTypes": [ "ctaElement", "imageElement" ],
"restrictedTypes": [ "videoElement" ]
}
}
}CMS (SaaS) checks the restriction against the section and component nodes that the composition contains directly. This check covers inline nodes and nodes that use a content reference. A section node is a boundary. CMS (SaaS) checks the section itself against the composition's types, but not the section's contents. The section's own composition constrains those contents, and CMS (SaaS) validates them when the section is saved.
Note CMS (SaaS) validates every item in a composition on every save, not only the items you changed. If you tighten allowedTypes after content exists, you can still read that content. The next save fails until you remove the items that are no longer allowed.
Layout compatibility
CMS (SaaS) rejects an allow list whose types can never appear in the configured layout. For example, only sections and section-enabled components can appear in an outline. The following request allows _page in an outline composition, so it fails. The error path is properties.sidebar.allowedTypes, and the message is The type '_page' cannot be used in a 'outline' layout composition.
{
"properties": {
"sidebar": {
"type": "composition",
"format": "outline",
"allowedTypes": [ "_page" ]
}
}
}To let a component appear in a composition, declare the matching composition behavior on its content type:
- sectionEnabled – For the section level of an outline.
- elementEnabled – For the element level of a grid.
See Standard fields.
Set a composition value
Write the built-in composition through the composition field of the content version. Write a custom composition property through properties.PROPERTY_KEY.value. Both fields take the same node tree.
The following request creates a landingPage experience with a value for each composition.
POST https://api.cms.optimizely.com/v1/content
Content-Type: application/json{
"contentType": "landingPage",
"container": "43f936c99b234ea397b261c538ad07c9",
"initialVersion": {
"displayName": "Autumn campaign",
"locale": "en",
"composition": {
"nodeType": "experience",
"layoutType": "outline",
"nodes": [
{
"displayName": "Hero",
"nodeType": "section",
"layoutType": "grid",
"component": {
"contentType": "BlankSection"
}
}
]
},
"properties": {
"sidebar": {
"value": {
"nodeType": "experience",
"layoutType": "grid",
"nodes": [
{
"displayName": "A row",
"nodeType": "row",
"nodes": [
{
"displayName": "A column",
"nodeType": "column",
"nodes": [
{
"displayName": "A call to action",
"nodeType": "component",
"component": {
"contentType": "ctaElement",
"properties": {
"heading": {
"value": "Book a demo"
}
}
}
}
]
}
]
}
]
}
}
}
}
}The root node of a composition reflects the content that owns it. Because sidebar belongs to an experience, its root node type is experience, even though its layout type is grid. Its rows sit directly under the root, with no section level in between.
Update a single composition
CMS (SaaS) stores each composition independently, so a partial update of one leaves the others untouched. The following request replaces the sidebar composition without affecting the built-in composition or any other composition property.
PATCH https://api.cms.optimizely.com/v1/content/6946107a8ad6414f8f1786364dab1ec2/versions/1253
Content-Type: application/merge-patch+json{
"properties": {
"sidebar": {
"value": {
"nodeType": "experience",
"layoutType": "grid",
"nodes": [ ]
}
}
}
}Query a composition property
CMS (SaaS) indexes each custom composition property to Optimizely Graph as a field named after the property key. The field has the type CompositionStructureNode, the same type as the built-in composition field. Query both in the same request and reuse the same fragment for each. See Visual Builder queries.
Composition error messages
The following table lists the errors specific to compositions. The error path points at composition for the built-in composition and at properties.PROPERTY_KEY for a custom composition property.
Error path | Message | Cause |
|---|---|---|
composition | The 'composition' field is only supported on content types with base type '_experience' or '_section'. | The request sets the composition field on another base type. |
properties.PROPERTY_KEY | Custom properties of type 'PropertyComposition' such as 'PROPERTY_KEY' are only supported on Experience content types. Section content types may use only the inherited built-in 'Composition' property. | The request declares a composition property on a content type that is not an experience. |
composition.format, properties.PROPERTY_KEY.format | The layout type 'LAYOUT_TYPE' is not a registered layout type. | format is not one of the available layout types. |
composition.format, properties.PROPERTY_KEY.format | The layout type of 'PROPERTY_KEY' cannot be changed from 'CURRENT_LAYOUT_TYPE' to 'NEW_LAYOUT_TYPE' because the property already has content. | The request changes the layout type after content uses the composition. |
composition.allowedTypes, properties.PROPERTY_KEY.allowedTypes | The allowedTypes field contains one or more invalid content types: 'CONTENT_TYPE_KEY'. | An entry does not match a content type key or base type. |
composition.allowedTypes, properties.PROPERTY_KEY.allowedTypes | The type 'CONTENT_TYPE_KEY' cannot be used in a 'LAYOUT_TYPE' layout composition. | An allowed type can never appear in the configured layout type. |