Search Docs
Loading...
Skip to content

UI Events

Listen to editor UI events, send custom events from editor configuration code, and route those events into your Android app state.

4 mins
estimated time
GitHub

Editor UI events are messages sent through the editor’s EditorEventHandler. Built-in editor components use them for actions such as changing view mode or starting export, and your configuration can send custom events for app-specific workflows.

Editor Events vs Engine Events#

Use UI events when the event belongs to the editor interface: a button tap, sheet transition, export request, or custom workflow step. The event flow is: editorContext.eventHandler.send(event) dispatches an EditorEvent, the editor handles known internal events when applicable, and onEvent receives internal and custom events for your app logic.

Use Events instead when you need CreativeEngine block lifecycle changes such as created, updated, or destroyed blocks. That guide uses engine.event.subscribe() and is separate from the editor UI event bus.

Define Custom Events#

Custom events are Kotlin objects or data classes that implement EditorEvent. Keep them small and specific to the UI workflow you want to observe.

object ShowLoading : EditorEvent
object HideLoading : EditorEvent
data class WorkflowStepChanged(
val label: String,
) : EditorEvent

Use Events for App State#

Keep UI state in regular Compose state and update it from onEvent. The event handler should decide what happened; composables read the state when rendering event-driven UI.

data class UiEventsState(
val isLoading: Boolean = false,
val lastEvent: String = "Waiting for editor events",
)
var state by remember { mutableStateOf(UiEventsState()) }

Observe Editor Events#

Configure onEvent inside EditorConfiguration.remember. The callback runs for built-in events and for the custom event types defined above.

onEvent = { event ->
state = when (event) {
ShowLoading -> state.copy(
isLoading = true,
lastEvent = "Started custom loading state",
)
HideLoading -> state.copy(
isLoading = false,
lastEvent = "Finished custom loading state",
)
is WorkflowStepChanged -> state.copy(lastEvent = event.label)
is EditorEvent.SetViewMode -> {
val viewMode = when (event.viewMode) {
is EditorViewMode.Edit -> "Edit"
is EditorViewMode.Preview -> "Preview"
is EditorViewMode.Pages -> "Pages"
}
state.copy(lastEvent = "View mode changed to $viewMode")
}
is EditorEvent.Export.Start -> {
state.copy(lastEvent = "Export requested")
}
else -> state
}
}

This example tracks EditorEvent.SetViewMode and EditorEvent.Export.Start as built-in UI events. The sample overlay sends those events from buttons so the reducer is reachable in the demo, and it handles custom events in the same reducer so app logic has a single event entry point.

Send Events from Editor UI#

Send custom events from editor callbacks or custom UI components through editorContext.eventHandler.send(...). The sample sends a workflow step after the editor finishes loading.

onLoaded = {
editorContext.eventHandler.send(
WorkflowStepChanged(label = "Editor loaded"),
)
}

The same handler is available from components configured through EditorConfiguration, so custom buttons can dispatch app-specific events without bypassing the editor event pipeline.

The overlay below sends built-in and custom events from buttons, then renders the last observed event plus a loading spinner from the same state object.

overlay = {
EditorComponent.remember {
decoration = {
val syncScope = rememberCoroutineScope()
Box(modifier = Modifier.fillMaxSize()) {
Text(
text = state.lastEvent,
modifier = Modifier
.align(Alignment.TopCenter)
.padding(top = 24.dp),
)
Column(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = 24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Button(
onClick = {
editorContext.eventHandler.send(
EditorEvent.SetViewMode(EditorViewMode.Preview()),
)
},
) {
Text("Preview")
}
Button(
onClick = {
editorContext.eventHandler.send(EditorEvent.Export.Start())
},
) {
Text("Request Export")
}
Button(
enabled = !state.isLoading,
onClick = {
syncScope.launch {
editorContext.eventHandler.send(ShowLoading)
editorContext.eventHandler.send(
WorkflowStepChanged(label = "Sync requested"),
)
// Simulate asynchronous app work before clearing the loading event.
delay(1_200)
editorContext.eventHandler.send(HideLoading)
}
},
) {
Text("Run Sync")
}
}
if (state.isLoading) {
CircularProgressIndicator(
modifier = Modifier.align(Alignment.Center),
)
}
}
}
}
}

API Reference#

API Description
EditorConfiguration.remember { onEvent = { ... } } Creates an editor configuration and registers the event observer.
editorContext.eventHandler.send(event=_) Dispatches a built-in or custom editor UI event.
EditorComponent.remember { decoration = { ... } } Creates a custom UI component that can send editor events from its callbacks.

Key Types#

Type Purpose
EditorEvent Base interface for built-in and custom editor UI events.
EditorEvent.SetViewMode(viewMode=_) Built-in event type that sets the editor view mode.
EditorEvent.Export.Start Built-in event sent by export actions before onExport runs.
ShowLoading, HideLoading, WorkflowStepChanged Custom events used by the sample to update app-side Compose state.

Next Steps#

  • Events - subscribe to CreativeEngine block lifecycle events.
  • Actions - trigger editor-driven automation flows with callbacks and events.
  • Overlay - render event-driven dialogs and loading states over the editor.