Search
Loading...
Skip to content

Register a New Component

Register custom UI components using CE.SDK’s builder system and place them in different areas of the editor interface like the navigation bar, inspector bar, dock, and canvas menu.

Register New Component

10 mins
estimated time
Download
StackBlitz
GitHub

The builder system provides a declarative API for creating UI components that integrate with CE.SDK. Components registered via cesdk.ui.registerComponent() receive a render function that is automatically re-invoked when relevant engine state changes, enabling reactive UIs without manual subscription management. You can create buttons, dropdowns, inputs, and other UI elements that react to engine state changes.

This guide demonstrates registering custom components including a button, dropdown menu, checkbox, and select control, then placing them in the navigation bar and inspector bar.

Registering a Component#

Use cesdk.ui.registerComponent() to register a component with a unique ID and a render function. The render function receives builder, engine, cesdk, state, and payload parameters.

// Register a custom button component that shows the selected block's type.
// The render function is automatically re-invoked when engine state changes.
cesdk.ui.registerComponent(
'com.example.blockTypeButton',
({ builder, engine: eng, cesdk: cesdkInstance }) => {
// Engine API calls are tracked. When the selection changes,
// the component re-renders automatically.
const selectedBlocks = eng.block.findAllSelected();
const selectedBlock =
selectedBlocks.length > 0 ? selectedBlocks[0] : null;
const blockType = selectedBlock
? eng.block.getType(selectedBlock)
: null;
const label = blockType ? formatBlockType(blockType) : 'No Selection';
builder.Button('block-type-display', {
label,
icon: '@imgly/icons/Info',
isDisabled: !selectedBlock,
onClick: () => {
const message = selectedBlock
? `Selected block type: ${blockType}`
: 'No block selected';
cesdkInstance.ui.showNotification({ message, type: 'info' });
}
});
}
);

Component ID Naming#

Use reverse domain notation for component IDs (e.g., 'com.example.myButton'). This ensures uniqueness and avoids conflicts with built-in components.

Render Function Signature#

The render function receives these parameters:

  • builder: Object providing methods to create UI elements
  • engine: The engine instance for accessing block and scene state
  • cesdk: The editor instance for UI operations like notifications
  • state: Function for managing local component state
  • payload: Optional data passed when adding the component to an order

Engine Reactivity#

Components automatically re-render when engine APIs called within the render function detect state changes. Engine method calls like engine.block.findAllSelected() are tracked, and only components that use changed engine state re-render.

In the example above, calling eng.block.findAllSelected() and eng.block.getType() inside the render function creates automatic subscriptions. When the selection changes, the component re-renders with updated values.

This reactive approach eliminates manual subscription management. The builder system handles all subscriptions internally.

Using Builder Elements#

The builder object provides methods to create UI elements within your component.

Button#

The builder.Button() method creates an interactive button. It accepts a unique ID and configuration options including label, icon, onClick, and state flags like isDisabled.

Use builder.Dropdown() to create a dropdown menu with nested content. The children callback function lets you add buttons and separators inside the dropdown.

// Register a component with a dropdown menu containing buttons.
// Dropdowns in the navigation bar support Button and Separator elements.
cesdk.ui.registerComponent(
'com.example.actionsDropdown',
({ builder, engine: eng, cesdk: cesdkInstance }) => {
const selectedBlocks = eng.block.findAllSelected();
const selectedBlock =
selectedBlocks.length > 0 ? selectedBlocks[0] : null;
builder.Dropdown('actions-dropdown', {
label: 'Actions',
icon: '@imgly/icons/Adjustments',
children: () => {
builder.Button('action-duplicate', {
label: 'Duplicate',
icon: '@imgly/icons/Duplicate',
variant: 'plain',
isDisabled: !selectedBlock,
onClick: () => {
if (selectedBlock) {
eng.block.duplicate(selectedBlock);
cesdkInstance.ui.showNotification({
message: 'Block duplicated',
type: 'info'
});
}
}
});
builder.Button('action-delete', {
label: 'Delete',
icon: '@imgly/icons/Trash',
variant: 'plain',
color: 'danger',
isDisabled: !selectedBlock,
onClick: () => {
if (selectedBlock) {
eng.block.destroy(selectedBlock);
cesdkInstance.ui.showNotification({
message: 'Block deleted',
type: 'info'
});
}
}
});
builder.Separator('action-separator');
builder.Button('action-select-all', {
label: 'Select All',
icon: '@imgly/icons/SelectAll',
variant: 'plain',
onClick: () => {
const page = eng.scene.getCurrentPage();
if (page) {
const children = eng.block.getChildren(page);
children.forEach((child) =>
eng.block.setSelected(child, true)
);
}
}
});
}
});
}
);

The dropdown receives the same configuration as buttons, but uses children instead of onClick to define the dropdown content.

Available Builder Components#

Not every location supports every builder component yet. The following table shows the available builder components and their properties.

Builder ComponentDescriptionProperties
builder.ButtonA simple button to react on a user click.label: The button label (supports i18n keys).
onClick: Click handler.
variant: regular (default) or plain.
color: accent or danger.
icon: The button icon.
trailingIcon: Trailing icon.
isActive: Active state indicator.
isSelected: Selected state indicator.
isDisabled: Disabled state.
isLoading: Loading state.
loadingProgress: Progress value 0-1.
tooltip: Hover tooltip (supports i18n keys).
builder.ButtonGroupGrouping of multiple buttons in a segmented control.children: Function to render grouped buttons (only Button and Dropdown allowed).
builder.DropdownA button that opens a dropdown with content.Same as Button, but with children instead of onClick for dropdown content.
builder.HeadingRenders text as a heading.content: The heading text.
builder.SeparatorAdds visual separation between entries.No properties. Follows special layout rules for consecutive separators.
builder.ComponentRenders another registered component.componentId: The registered component ID.
payload: Optional data passed to the component.
builder.CheckboxToggle checkbox control.value: Current value.
setValue: Change handler.
inputLabel: Checkbox label.
builder.SelectDropdown select with options.value: Current selection object.
setValue: Change handler.
values: Array of option objects with id, label, and optional icon.
builder.TextInputText input field.value: Current value.
setValue: Change handler.
placeholder: Placeholder text.
builder.NumberInputNumeric input field.value: Current value.
setValue: Change handler.
min/max: Range limits.
builder.SliderNumeric range slider.value: Current value.
setValue: Change handler.
min/max/step: Range configuration.
builder.SectionContainer for grouping related controls.children: Function to render section contents.

Managing Component State#

The state function provides local state management within components, similar to React’s useState.

const { value, setValue } = state('unique-id', defaultValue);

State persists across re-renders with the same ID. Calling setValue() triggers a component re-render. Since the returned object matches input component expectations, you can spread it directly into components.

cesdk.ui.registerComponent('counter', ({ builder, state }) => {
const { value, setValue } = state('counter', 0);
builder.Button('counter-button', {
label: `${value} clicks`,
onClick: () => {
setValue(value + 1);
}
});
});

Placing Components in the Navigation Bar#

Add components to the navigation bar using cesdk.ui.setNavigationBarOrder(). The navigation bar appears at the top of the editor.

// Place the custom components in the navigation bar.
// Use setNavigationBarOrder to define the order of components.
cesdk.ui.setNavigationBarOrder([
'ly.img.save',
'com.example.blockTypeButton',
'com.example.actionsDropdown',
'ly.img.spacer',
'ly.img.undo',
'ly.img.redo',
'ly.img.zoom.navigationBar'
]);

Use cesdk.ui.insertNavigationBarOrderComponent() to position components relative to existing ones without replacing the entire order.

Placing Components in the Inspector Bar#

The inspector bar appears at the bottom when a block is selected. Add components using cesdk.ui.setInspectorBarOrder() or position relative to existing components with cesdk.ui.insertInspectorBarOrderComponent().

cesdk.ui.setInspectorBarOrder([
'com.example.myInspectorButton',
'ly.img.fill',
'ly.img.stroke'
]);

Placing Components in the Dock#

The dock is the vertical sidebar for asset libraries and tools. Add components using cesdk.ui.setDockOrder() or cesdk.ui.insertDockOrderComponent().

cesdk.ui.insertDockOrderComponent(
{ id: 'ly.img.assetLibrary.dock' },
'com.example.myDockButton',
'after'
);

Placing Components in the Canvas Menu#

The canvas menu appears as a floating menu near selected blocks. Add components using cesdk.ui.setCanvasMenuOrder() or cesdk.ui.insertCanvasMenuOrderComponent().

cesdk.ui.setCanvasMenuOrder([
'ly.img.delete',
'com.example.myCanvasMenuAction',
'ly.img.duplicate'
]);

Placing Components in the Canvas Bar#

Canvas bars appear above or below the canvas area. Specify 'top' or 'bottom' position using cesdk.ui.setCanvasBarOrder() or cesdk.ui.insertCanvasBarOrderComponent().

cesdk.ui.setCanvasBarOrder(['com.example.myCanvasBarButton'], 'top');

Passing Payload Data#

Components can receive contextual data through the payload parameter. Pass data when adding a component to an order using an object with id and additional properties.

cesdk.ui.registerComponent(
'myDockEntry.dock',
({ builder: { Button }, payload }) => {
const { label } = payload;
Button('entry-button', { label });
}
);
cesdk.ui.setDockOrder([
{
id: 'myDockEntry.dock',
label: 'Custom Label'
}
]);

Use TypeScript generics with registerComponent<PayloadType>() to type the payload parameter.

Troubleshooting#

Component Not Rendering#

Verify the component ID matches between registration and placement in order arrays. Check that the registration happens before setting the order. Component IDs are case-sensitive.

State Not Persisting#

Ensure unique state IDs within the component. Duplicate IDs cause conflicts and unexpected behavior. Each state() call should use a distinct identifier.

Component Not Updating#

Confirm engine API calls are made inside the render function, not outside. The reactor only tracks calls made during the render function execution. Moving engine calls outside breaks reactivity.

Order Changes Not Applying#

Check that the order method matches the UI location. Use setDockOrder() for the dock, setNavigationBarOrder() for navigation, and so on. Mismatched methods silently fail.

API Reference#

MethodCategoryPurpose
cesdk.ui.registerComponent()Component RegistrationRegister a custom component with a unique ID and render function
cesdk.ui.setNavigationBarOrder()UI LayoutSet the order of components in the navigation bar
cesdk.ui.getNavigationBarOrder()UI LayoutGet the current navigation bar component order
cesdk.ui.insertNavigationBarOrderComponent()UI LayoutInsert a component relative to an existing navigation bar component
cesdk.ui.setInspectorBarOrder()UI LayoutSet the order of components in the inspector bar
cesdk.ui.getInspectorBarOrder()UI LayoutGet the current inspector bar component order
cesdk.ui.insertInspectorBarOrderComponent()UI LayoutInsert a component relative to an existing inspector bar component
cesdk.ui.setDockOrder()UI LayoutSet the order of components in the dock
cesdk.ui.getDockOrder()UI LayoutGet the current dock component order
cesdk.ui.insertDockOrderComponent()UI LayoutInsert a component relative to an existing dock component
cesdk.ui.setCanvasMenuOrder()UI LayoutSet the order of components in the canvas menu
cesdk.ui.getCanvasMenuOrder()UI LayoutGet the current canvas menu component order
cesdk.ui.insertCanvasMenuOrderComponent()UI LayoutInsert a component relative to an existing canvas menu component
cesdk.ui.setCanvasBarOrder()UI LayoutSet the order of components in the canvas bar (top or bottom)
cesdk.ui.getCanvasBarOrder()UI LayoutGet the current canvas bar component order
cesdk.ui.insertCanvasBarOrderComponent()UI LayoutInsert a component relative to an existing canvas bar component
builder.Button()BuilderCreate an interactive button element
builder.Dropdown()BuilderCreate a dropdown menu with nested children
builder.ButtonGroup()BuilderCreate a group of related buttons
builder.Checkbox()BuilderCreate a toggle checkbox control
builder.Select()BuilderCreate a select dropdown with predefined options
builder.TextInput()BuilderCreate a text input field
builder.NumberInput()BuilderCreate a numeric input field
builder.Slider()BuilderCreate a numeric slider control
builder.Section()BuilderCreate a container for grouping controls
builder.Separator()BuilderCreate a visual divider
builder.Heading()BuilderCreate a heading text element
builder.Component()BuilderRender another registered component with optional payload
state()Component StateAccess local state with get/set capabilities