Search Docs
Loading...
Skip to content

Canvas Menu

The canvas menu is the floating toolbar that appears next to a selected design block. Configure its item list, adjust existing entries, and add custom actions from your Android editor configuration.

A selected design block with the Android canvas menu floating above it

7 mins
estimated time
GitHub

Canvas Menu Architecture#

The canvas menu is an EditorComponent that the editor positions next to the current selection. It appears only when the editor state and selected block make quick actions relevant.

You assemble the menu from these component entries and related types:

  • CanvasMenu.Button - A button entry. Use predefined factories such as CanvasMenu.Button.rememberDuplicate() or create your own button.
  • CanvasMenu.Divider - A visual separator between groups of related actions.
  • EditorComponent - The base component type for fully custom canvas menu items.

The related CanvasMenu.Scope exposes the editor context, selected element, and helper state such as group membership or layer movement support to canvas menu configuration callbacks.

For a complete product surface, start from the Design Editor Starter Kit. This guide focuses on the canvas menu configuration that you can apply to your own editor setup.

Configuration#

Canvas menu customization lives in EditorConfiguration. The Editor composable owns Engine startup; these snippets use the existing editor context and configure only the canvas menu surface.

EditorConfiguration.remember {
canvasMenu = {
CanvasMenu.remember {
listBuilder = {
CanvasMenu.ListBuilder.remember {
add { CanvasMenu.Button.rememberDuplicate() }
add { CanvasMenu.Button.rememberDelete() }
}
}
}
}
}

CanvasMenu.remember keeps the default visibility and decoration unless you override them, but it does not add items on its own. Assign listBuilder to populate the menu. By default, the menu appears when a design block is selected, touch interaction is idle, no sheet is open, the selection is neither an audio block nor a page, the editor is not in text edit mode, the scene is paused, and the selected block is visible at the current playback time. The default decoration positions the toolbar near the selected block.

The Configuration guide covers editor setup more broadly; this page covers the canvas menu portion of that setup.

Declaring the Item List#

Use CanvasMenu.ListBuilder.remember to declare the complete list of canvas menu items. The order of add calls is the display order, and the list replaces the menu contents for this configuration.

CanvasMenu.ListBuilder.remember {
add {
CanvasMenu.Button.remember {
id = { EditorComponentId("com.example.canvasMenu.button.review") }
onClick = {
Toast
.makeText(editorContext.activity, "Review action", Toast.LENGTH_SHORT)
.show()
}
vectorIcon = null
textString = { "Review" }
contentDescription = { "Review selected block" }
}
}
add { CanvasMenu.Button.rememberSelectGroup() }
if (editorContext.isSelectionInGroup) {
add {
CanvasMenu.Divider.remember()
}
}
add { CanvasMenu.Button.rememberSendBackward() }
add { CanvasMenu.Button.rememberBringForward() }
if (editorContext.canSelectionMove) {
add {
CanvasMenu.Divider.remember()
}
}
add { CanvasMenu.Button.rememberDuplicate() }
add { CanvasMenu.Button.rememberDelete() }
}
  • Predefined buttons include common actions such as duplicate, delete, layer reordering, and selecting a parent group.
  • CanvasMenu.Divider.remember() separates action groups.
  • Custom buttons can be placed alongside predefined items when the action belongs directly in the contextual toolbar.

Modify Canvas Menu Items#

Use modify when you already have a list builder and only need to add, replace, or remove a few entries. Call it on the builder instance you want to adjust.

existingListBuilder.modify {
addFirst {
CanvasMenu.Button.remember {
id = { EditorComponentId("com.example.canvasMenu.button.first") }
vectorIcon = null
textString = { "First" }
onClick = {}
}
}
addLast {
CanvasMenu.Button.remember {
id = { EditorComponentId("com.example.canvasMenu.button.last") }
vectorIcon = null
textString = { "Last" }
onClick = {}
}
}
addAfter(id = CanvasMenu.Button.Id.bringForward, failIfNotFound = true) {
CanvasMenu.Button.remember {
id = { EditorComponentId("com.example.canvasMenu.button.afterBringForward") }
vectorIcon = null
textString = { "After Forward" }
onClick = {}
}
}
addBefore(id = CanvasMenu.Button.Id.sendBackward, failIfNotFound = true) {
CanvasMenu.Button.remember {
id = { EditorComponentId("com.example.canvasMenu.button.beforeSendBackward") }
vectorIcon = null
textString = { "Before Backward" }
onClick = {}
}
}
replace(id = CanvasMenu.Button.Id.duplicate, failIfNotFound = true) {
CanvasMenu.Button.rememberDuplicate {
vectorIcon = { IconPack.Music }
}
}
remove(id = CanvasMenu.Button.Id.delete, failIfNotFound = true)
}
Operation Purpose
addFirst Add an item at the beginning.
addLast Add an item at the end.
addAfter Insert an item after a target ID.
addBefore Insert an item before a target ID.
replace Replace the item with the target ID.
remove Remove the item with the target ID.

Canvas Menu Item Configuration#

Canvas menu entries are editor components. Each entry needs a unique EditorComponentId so the list builder can target it safely.

Predefined Buttons#

CE.SDK ships factory functions for common canvas actions. Use them when the built-in behavior matches the action you need, and see the full list of available factories below.

@Composable
fun rememberPredefinedCanvasMenuButton() = CanvasMenu.Button.rememberDuplicate()

Customize Predefined Buttons#

Pass a builder block to a predefined factory when you want to override selected properties while keeping the rest of the factory behavior.

@Composable
fun rememberCustomizedDeleteButton() = CanvasMenu.Button.rememberDelete {
textString = { "Remove" }
contentDescription = { "Remove selected block" }
enabled = {
editorContext.selection.type != DesignBlockType.Text
}
}

The default delete button is icon-only and is visible when the selected block allows lifecycle/destroy. This example keeps the delete action and default visibility gate, then adds a visible label, overrides the accessibility description, and sets a separate enabled predicate that disables the button for text blocks.

Create New Buttons#

Create a new CanvasMenu.Button when the action is specific to your app. Use a stable, unique ID and provide the action, icon, text, and accessibility description.

@Composable
fun rememberReviewCanvasMenuButton() = CanvasMenu.Button.remember {
id = { EditorComponentId("com.example.canvasMenu.button.review") }
onClick = {
Toast
.makeText(editorContext.activity, "Review action", Toast.LENGTH_SHORT)
.show()
}
vectorIcon = { IconPack.Music }
textString = { "Review" }
contentDescription = { "Review selected block" }
}

Use onClick for your app-specific behavior. The button still participates in the canvas menu’s visibility and item decoration like every other menu entry.

Dividers#

Use CanvasMenu.Divider.remember() to separate related actions. You can keep the default divider or customize its modifier, visibility, and decoration.

@Composable
fun rememberCanvasMenuDivider() = CanvasMenu.Divider.remember {
modifier = {
remember(this) {
Modifier
.padding(horizontal = 8.dp)
.size(width = 1.dp, height = 24.dp)
}
}
}

Create Custom Items#

Use EditorComponent.remember when a button or divider is not enough. A custom item owns its rendering through decoration, so it is responsible for layout, click handling, and accessibility behavior.

@Composable
fun rememberCanvasMenuCustomItem() = EditorComponent.remember {
id = { EditorComponentId("com.example.canvasMenu.customItem") }
decoration = {
Box(
modifier = Modifier
.fillMaxHeight()
.clickable {
Toast
.makeText(editorContext.activity, "Custom item clicked", Toast.LENGTH_SHORT)
.show()
},
) {
Text(
modifier = Modifier.align(Alignment.Center),
text = "Review",
)
}
}
}

List of Available Canvas Menu Buttons#

The predefined buttons live in the CanvasMenu.Button namespace. Most predefined buttons are icon-only with accessibility descriptions, while CanvasMenu.Button.rememberSelectGroup() is text-only. Each factory also provides its default visibility and action behavior.

Button ID constant Default behavior
CanvasMenu.Button.rememberBringForward() CanvasMenu.Button.Id.bringForward Brings the selected block forward when layer movement is possible.
CanvasMenu.Button.rememberSendBackward() CanvasMenu.Button.Id.sendBackward Sends the selected block backward when layer movement is possible.
CanvasMenu.Button.rememberDuplicate() CanvasMenu.Button.Id.duplicate Duplicates the selected block when its lifecycle/duplicate scope is allowed.
CanvasMenu.Button.rememberDelete() CanvasMenu.Button.Id.delete Deletes the selected block when its lifecycle/destroy scope is allowed.
CanvasMenu.Button.rememberSelectGroup() CanvasMenu.Button.Id.selectGroup Selects the group that contains the selected block.

API Reference#

API Category Purpose
EditorConfiguration.remember(builder=_) Config Create the editor configuration that assigns canvasMenu.
CanvasMenu.remember(builder=_) Config Create and configure the canvas menu component.
CanvasMenu.ListBuilder.remember(builder=_) Config Declare a complete canvas menu item list.
listBuilder.modify(builder=_) Config Adjust an existing list builder instance.
modify.addFirst(block=_) List operation Add an item at the beginning.
modify.addLast(block=_) List operation Add an item at the end.
modify.addAfter(id=_, failIfNotFound=_, block=_) List operation Insert an item after a target ID.
modify.addBefore(id=_, failIfNotFound=_, block=_) List operation Insert an item before a target ID.
modify.replace(id=_, failIfNotFound=_, block=_) List operation Replace an item by ID.
modify.remove(id=_, failIfNotFound=_) List operation Remove an item by ID.
CanvasMenu.Button.rememberBringForward(builder=_) Item Create the predefined bring-forward button.
CanvasMenu.Button.rememberSendBackward(builder=_) Item Create the predefined send-backward button.
CanvasMenu.Button.rememberDuplicate(builder=_) Item Create the predefined duplicate button.
CanvasMenu.Button.rememberDelete(builder=_) Item Create the predefined delete button.
CanvasMenu.Button.rememberSelectGroup(builder=_) Item Create the predefined select-group button.
CanvasMenu.Button.remember(builder=_) Item Create a custom canvas menu button.
CanvasMenu.Divider.remember(builder=_) Layout Create a divider item.
EditorComponent.remember(builder=_) Item Create a fully custom menu item.
engine.block.isAllowedByScope(block=_, key=_) Support check Check whether the selected block allows a scope before enabling a custom action.

Next Steps#

  • Dock - Configure the bottom toolbar that opens asset libraries and sheets.
  • Inspector Bar - Configure context-sensitive controls for the selected block.
  • Navigation Bar - Configure the top bar with close, undo, and redo.
  • Asset Library - Configure sources shared across editor components.