Display settings and templates
Create and use display templates in Optimizely CMS to style components, sections, and structural nodes with editor-configurable settings.
Define visual variations that editors can apply to components, sections, and structural nodes in Visual Builder. After developers create the templates, editors can select predefined styles directly in the Visual Builder UI without writing code.
Create display templates
Display templates can target three different levels:
- Base type –
_experience,_section, or_component. - Content type – Specific content types derived from base types (e.g.,
Tile,Hero). - Node type – Structural nodes:
roworcolumn.
Example: Component display template
Here's how to create a display template for a component:
import { contentType, displayTemplate, Infer } from '@optimizely/cms-sdk';
export const TileContentType = contentType({
key: 'Tile',
displayName: 'Tile Component',
baseType: '_component',
properties: {
title: { type: 'string' },
description: { type: 'string' },
},
compositionBehaviors: ['elementEnabled'],
});
export const SquareDisplayTemplate = displayTemplate({
key: 'SquareDisplayTemplate',
isDefault: false,
displayName: 'Square Display Template',
baseType: '_component',
settings: {
color: {
editor: 'select',
displayName: 'Description Font Color',
sortOrder: 0,
choices: {
yellow: {
displayName: 'Yellow',
sortOrder: 1,
},
green: {
displayName: 'Green',
sortOrder: 2,
},
orange: {
displayName: 'Orange',
sortOrder: 3,
},
},
},
orientation: {
editor: 'select',
displayName: 'Orientation',
sortOrder: 1,
choices: {
vertical: { displayName: 'Vertical', sortOrder: 1 },
horizontal: { displayName: 'Horizontal', sortOrder: 2 },
},
},
},
tag: 'Square',
});Example: Row display template
Defines a default display template for a row structural node with configurable padding options:
export const TileRowDisplayTemplate = displayTemplate({
key: 'TileRowDisplayTemplate',
isDefault: true,
displayName: 'Tile Row Display Template',
nodeType: 'row',
settings: {
padding: {
editor: 'select',
displayName: 'Padding',
sortOrder: 0,
choices: {
small: {
displayName: 'Small',
sortOrder: 1,
},
medium: {
displayName: 'Medium',
sortOrder: 2,
},
large: {
displayName: 'Large',
sortOrder: 3,
},
},
},
},
});Example: Column display template
Defines a default display template for a column structural node with configurable background color options:
export const TileColumnDisplayTemplate = displayTemplate({
key: 'TileColumnDisplayTemplate',
isDefault: true,
displayName: 'Tile Column Display Template',
nodeType: 'column',
settings: {
background: {
editor: 'select',
displayName: 'Background Color',
sortOrder: 0,
choices: {
red: {
displayName: 'Red',
sortOrder: 1,
},
black: {
displayName: 'Black',
sortOrder: 2,
},
grey: {
displayName: 'Grey',
sortOrder: 3,
},
},
},
},
});Display setting editors
Display settings support two editor types that determine how editors interact with the setting:
Select Editor
A drop-down list supporting single-item selection. This is the most common editor type.
settings: {
color: {
editor: 'select',
displayName: 'Text Color',
sortOrder: 0,
choices: {
blue: { displayName: 'Blue', sortOrder: 1 },
red: { displayName: 'Red', sortOrder: 2 },
green: { displayName: 'Green', sortOrder: 3 },
},
},
}Behavior of the code above:
- Editors see a drop-down with all choices.
- Single selection only.
- Values are the choice keys (e.g.,
'blue','red','green').
Checkbox editor
To implement a Boolean toggle:
settings: {
showBorder: {
editor: 'checkbox',
displayName: 'Show Border',
sortOrder: 0,
choices: {
true: { displayName: 'Enabled', sortOrder: 1 },
false: { displayName: 'Disabled', sortOrder: 2 },
},
},
}Behavior:
- Editors see a checkbox toggle.
- Returns
trueorfalse. - Choices define the display labels but the value is always Boolean.
Use display settings in components
To use display settings in your component, add a displaySettings prop typed with Infer<typeof YourDisplayTemplate>:
import { Infer } from '@optimizely/cms-sdk';
import { getPreviewUtils } from '@optimizely/cms-sdk/react/server';
type Props = {
opti: Infer<typeof TileContentType>;
displaySettings?: Infer<typeof SquareDisplayTemplate>;
};
export function SquareTile({ opti, displaySettings }: Props) {
const { pa } = getPreviewUtils(opti);
return (
<div className="square-tile">
<h4 {...pa('title')}>{opti.title}</h4>
<p
style={{
color: displaySettings?.color,
flexDirection:
displaySettings?.orientation === 'horizontal' ? 'row' : 'column',
}}
{...pa('description')}
>
{opti.description}
</p>
</div>
);
}
NoteImportant points:
displaySettingsis optional (?) as it may not always be present.- Use optional chaining (
displaySettings?.color) to safely access values.- The values correspond to the choice keys you defined.
- TypeScript provides autocomplete for available settings and choices.
Creating default and variant components
You can have a default component and variants that use different display templates:
// Default component without display settings
export default function Tile({ opti }: Props) {
const { pa } = getPreviewUtils(opti);
return (
<div className="tile">
<h1 {...pa('title')}>{opti.title}</h1>
<p {...pa('description')}>{opti.description}</p>
</div>
);
}
// Variant component with display settings
export function SquareTile({ opti, displaySettings }: Props) {
const { pa } = getPreviewUtils(opti);
return (
<div className="square-tile">
<h4 {...pa('title')}>{opti.title}</h4>
<p
style={{
color: displaySettings?.color,
flexDirection:
displaySettings?.orientation === 'horizontal' ? 'row' : 'column',
}}
{...pa('description')}
>
{opti.description}
</p>
</div>
);
}Register display templates
Display templates must be registered in your application setup:
import { initDisplayTemplateRegistry } from '@optimizely/cms-sdk';
import {
SquareDisplayTemplate,
TileRowDisplayTemplate,
TileColumnDisplayTemplate,
} from '@/components/Tile';
initDisplayTemplateRegistry([
SquareDisplayTemplate,
TileRowDisplayTemplate,
TileColumnDisplayTemplate,
// ... other display templates
]);Using the tag property
tag propertyThe tag property links a display template to a specific component variant:
export const SquareDisplayTemplate = displayTemplate({
key: 'SquareDisplayTemplate',
// ... other properties
tag: 'Square', // Links to SquareTile component
});When registering components, you can use either of two patterns to associate the variant:
Pattern 1: Using tags object (recommended)
import { initReactComponentRegistry } from '@optimizely/cms-sdk/react/server';
import Tile, { SquareTile } from '@/components/Tile';
initReactComponentRegistry({
resolver: {
Tile: {
default: Tile, // Default component
tags: {
Square: SquareTile, // Variant for 'Square' tag
},
},
// ... other components
},
});Pattern 2: Using colon notation
initReactComponentRegistry({
resolver: {
'Tile:Square': SquareTile, // Variant for 'Square' tag
Tile: Tile, // Default/fallback component
// ... other components
},
});Both patterns work identically. The SDK will:
- First check for a tagged variant (e.g.,
Tile:Square). - If found, use that component.
- If not found, fall back to the default component.
The tag name in the display template matches either the key in the tags object (Pattern 1) or the string after the colon (Pattern 2).
Display template properties
Required properties
key– Unique identifier for the display template.displayName– Human-readable name shown to editors.isDefault– Whether this is the default template (one perbaseType/contentType/nodeType).settings– Object defining available settings and their options.
Target properties (choose one)
baseType– Apply to'_component','_experience', or'_section'.contentType– Apply to a specific content type key.nodeType– Apply to'row'or'column'.
Optional properties
tag– Links to a specific component variant (e.g.,'Square').sortOrder– Controls display order in the CMS UI.
Complete example
Here's a complete example bringing everything together:
import { contentType, displayTemplate, Infer } from '@optimizely/cms-sdk';
import { getPreviewUtils } from '@optimizely/cms-sdk/react/server';
// Content Type
export const TileContentType = contentType({
key: 'Tile',
displayName: 'Tile Component',
baseType: '_component',
properties: {
title: { type: 'string' },
description: { type: 'string' },
},
compositionBehaviors: ['elementEnabled'],
});
// Display Template
export const SquareDisplayTemplate = displayTemplate({
key: 'SquareDisplayTemplate',
isDefault: false,
displayName: 'Square Display Template',
baseType: '_component',
settings: {
color: {
editor: 'select',
displayName: 'Description Font Color',
sortOrder: 0,
choices: {
yellow: { displayName: 'Yellow', sortOrder: 1 },
green: { displayName: 'Green', sortOrder: 2 },
orange: { displayName: 'Orange', sortOrder: 3 },
},
},
orientation: {
editor: 'select',
displayName: 'Orientation',
sortOrder: 1,
choices: {
vertical: { displayName: 'Vertical', sortOrder: 1 },
horizontal: { displayName: 'Horizontal', sortOrder: 2 },
},
},
},
tag: 'Square',
});
// Component Types
type Props = {
opti: Infer<typeof TileContentType>;
displaySettings?: Infer<typeof SquareDisplayTemplate>;
};
// Default Component
export default function Tile({ opti }: Props) {
const { pa } = getPreviewUtils(opti);
return (
<div className="tile">
<h1 {...pa('title')}>{opti.title}</h1>
<p {...pa('description')}>{opti.description}</p>
</div>
);
}
// Variant Component with Display Settings
export function SquareTile({ opti, displaySettings }: Props) {
const { pa } = getPreviewUtils(opti);
return (
<div className="square-tile">
<h4 {...pa('title')}>{opti.title}</h4>
<p
style={{
color: displaySettings?.color,
flexDirection:
displaySettings?.orientation === 'horizontal' ? 'row' : 'column',
}}
{...pa('description')}
>
{opti.description}
</p>
</div>
);
}Display templates give editors powerful styling control while keeping your codebase maintainable and type-safe.
Updated about 22 hours ago
