Disclaimer: This website requires Please enable JavaScript in your browser settings for the best experience.

HomeDev GuideRecipesAPI Reference
Dev GuideAPI ReferenceUser GuideGitHubNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

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: row or column.

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 true or false.
  • 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>
  );
}
📘

Note

Important points:

  • displaySettings is 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

The 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:

  1. First check for a tagged variant (e.g., Tile:Square).
  2. If found, use that component.
  3. 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 per baseType/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.