The inspector bar provides context-sensitive editing controls that appear when you select a design element, offering tools specific to that element type like text formatting, image adjustments, or shape properties. This guide shows you how to customize these editing controls to match your app’s feature set and user experience goals. While examples use the Design Editor, the same configuration principles apply to all editor solutions.
Explore a complete code sample on GitHub.
Inspector Bar Architecture#
The inspector bar displays horizontally at the bottom when a design element is selected. It contains context-sensitive editing tools that adapt based on the selected element type (text, image, video, etc.).
Key Components:
InspectorBar.Item
- Abstract class that all inspector items inherit fromInspectorBar.Button
- Pre-built button implementation with icon and textInspectorBar.Custom
- Fully custom component for arbitrary content renderingInspectorBar.Scope
- Provides access to the engine, event handler, and selected element
Configuration#
Inspector bar customization is part of the EditorConfiguration
, therefore, in order to configure the inspector bar we need to configure the EditorConfiguration
. Below you can find the list of available configurations of the inspector bar. To demonstrate the default values, all parameters are assigned to their default values.
Available configuration parameters:
-
scope
- the scope of this component. Every new value will trigger recomposition of all the lambda parameters below. If you need to accessEditorScope
to construct the scope, useLocalEditorScope
. Consider using ComposeState
objects in the lambda parameters below for granular recompositions over updating the scope, since scope change triggers full recomposition of the inspector bar. Prefer updating individualInspectorBar.Item
s over updating the whole inspector bar. Ideally, scope should be updated when the parent scope (scope of the parent component) is updated and when you want to observe changes from theEngine
. -
visible
- Control inspector bar visibility based on selection state. Default value is always true. -
enterTransition
- Animation for when the inspector bar appears. By default, a vertical slide in animation is used. -
exitTransition
- Animation for when the inspector bar disappears. By default, a vertical slide out animation is used. -
decoration
- Apply custom styling like background, shadows, and padding. Default value is always no decoration. -
listBuilder
- Define the complete list of inspector bar items and their order. Items are only displayed whenvisible
returnstrue
. -
horizontalArrangement
- Layout arrangement for inspector bar items. Controls spacing and alignment of items within the inspector bar. Default value isArrangement.Start
. -
itemDecoration
- decoration of the items in the inspector bar. Useful when you want to add custom background, foreground, shadow, paddings etc to the items. Prefer using this decoration when you want to apply the same decoration to all the items, otherwise set decoration to individual items. Default value is always no decoration. -
itemsRowEnterTransition
- Animation for when the items row appears. By default, a horizontal slide in animation is used. -
itemsRowExitTransition
- Animation for when the items row disappears. Default value is always no exit transition.
val editorConfiguration = EditorConfiguration.rememberForDesign( inspectorBar = { InspectorBar.remember( // Implementation is too large, check the implementation of InspectorBar.defaultScope scope = InspectorBar.defaultScope, visible = { editorContext.safeSelection != null }, // Also available via InspectorBar.defaultEnterTransition enterTransition = { remember { slideInVertically( animationSpec = tween( durationMillis = 400, easing = CubicBezierEasing(0.05f, 0.7f, 0.1f, 1f), ), initialOffsetY = { it }, ) } }, // Also available via InspectorBar.defaultExitTransition exitTransition = { remember { slideOutVertically( animationSpec = tween( durationMillis = 150, easing = CubicBezierEasing(0.3f, 0f, 0.8f, 0.15f), ), targetOffsetY = { it }, ) } }, // Implementation is too large, check the implementation of InspectorBar.DefaultDecoration decoration = { DefaultDecoration { it() } }, listBuilder = InspectorBar.ListBuilder.remember(), horizontalArrangement = { Arrangement.Start }, // Also available via InspectorBar.defaultItemsRowEnterTransition itemsRowEnterTransition = { remember { slideInHorizontally( animationSpec = tween(400, easing = CubicBezierEasing(0.05F, 0.7F, 0.1F, 1F)), initialOffsetX = { it / 3 }, ) } }, // Also available via InspectorBar.defaultItemsRowExitTransition itemsRowExitTransition = { ExitTransition.None }, // default value is { it() } itemDecoration = { Box(modifier = Modifier.padding(2.dp)) { it() } }, ) },)
ListBuilder Configuration#
You can configure the complete item list or modify the default items using two main approaches:
Available approaches:
-
InspectorBar.ListBuilder.remember()
- Define the complete list of inspector bar items from scratch. Use this when you want full control over the inspector bar configuration. -
InspectorBar.ListBuilder.remember().modify()
- Modify the default item list by adding, replacing, or removing specific items without rebuilding the entire configuration. Use this when you want to keep most defaults but make targeted changes.
The InspectorBar.Scope
provides access to the engine, event handler, and selected element state. Use this for advanced customization logic and to maintain consistency with the current editor context.
Default Inspector Bar Items#
The default configuration includes all essential editing tools for different element types:
@Composablefun InspectorBar.ListBuilder.remember() = InspectorBar.ListBuilder.remember { add { InspectorBar.Button.rememberReplace() } // Video, Image, Sticker, Audio add { InspectorBar.Button.rememberEditText() } // Text add { InspectorBar.Button.rememberFormatText() } // Text add { InspectorBar.Button.rememberFillStroke() } // Page, Video, Image, Shape, Text add { InspectorBar.Button.rememberTextBackground() } // Text add { InspectorBar.Button.rememberVolume() } // Video, Audio add { InspectorBar.Button.rememberCrop() } // Video, Image add { InspectorBar.Button.rememberAdjustments() } // Video, Image add { InspectorBar.Button.rememberFilter() } // Video, Image add { InspectorBar.Button.rememberEffect() } // Video, Image add { InspectorBar.Button.rememberBlur() } // Video, Image add { InspectorBar.Button.rememberShape() } // Video, Image, Shape add { InspectorBar.Button.rememberSelectGroup() } // Video, Image, Sticker, Shape, Text add { InspectorBar.Button.rememberEnterGroup() } // Group add { InspectorBar.Button.rememberLayer() } // Video, Image, Sticker, Shape, Text add { InspectorBar.Button.rememberSplit() } // Video, Image, Sticker, Shape, Text, Audio add { InspectorBar.Button.rememberMoveAsClip() } // Video, Image, Sticker, Shape, Text add { InspectorBar.Button.rememberMoveAsOverlay() } // Video, Image, Sticker, Shape, Text add { InspectorBar.Button.rememberReorder() } // Video, Image, Sticker, Shape, Text add { InspectorBar.Button.rememberDuplicate() } // Video, Image, Sticker, Shape, Text, Audio add { InspectorBar.Button.rememberDelete() } // Video, Image, Sticker, Shape, Text, Audio}
Modify Inspector Bar Items#
Use the modify
function to adjust the default item list without rebuilding the entire configuration:
listBuilder = InspectorBar.ListBuilder.remember().modify {
Available modification operations:
addFirst
- prepends a new item at the beginning:
addFirst { InspectorBar.Button.remember( id = EditorComponentId("my.package.inspectorBar.button.first"), vectorIcon = null, text = { "First Button" }, onClick = {}, )}
addLast
- appends a new item at the end:
addLast { InspectorBar.Button.remember( id = EditorComponentId("my.package.inspectorBar.button.last"), vectorIcon = null, text = { "Last Button" }, onClick = {}, )}
addAfter
- adds a new item right after a specific item:
addAfter(id = InspectorBar.Button.Id.layer) { InspectorBar.Button.remember( id = EditorComponentId("my.package.inspectorBar.button.afterLayer"), vectorIcon = null, text = { "After Layer" }, onClick = {}, )}
addBefore
- adds a new item right before a specific item:
addBefore(id = InspectorBar.Button.Id.crop) { InspectorBar.Button.remember( id = EditorComponentId("my.package.inspectorBar.button.beforeCrop"), vectorIcon = null, text = { "Before Crop" }, onClick = {}, )}
replace
- replaces an existing item with a new item:
replace(id = InspectorBar.Button.Id.formatText) { InspectorBar.Button.remember( id = EditorComponentId("my.package.inspectorBar.button.replacedFormatText"), vectorIcon = null, text = { "Replaced Format Text" }, onClick = {}, )}
remove
- removes an existing item:
remove(id = InspectorBar.Button.Id.delete)
InspectorBar.Item Configuration#
Each InspectorBar.Item
is an EditorComponent
. Its id
must be unique which is a requirement for proper component management.
You have multiple options for creating inspector bar items, from simple predefined buttons to fully custom implementations.
Use Predefined Buttons#
Start with predefined buttons which are provided as composable functions. All available predefined buttons are listed below.
Create New Buttons#
Create custom buttons when predefined options don’t meet your needs:
@Composablefun rememberInspectorBarButton() = InspectorBar.Button.remember( id = EditorComponentId("my.package.inspectorBar.button.newButton"), scope = LocalEditorScope.current.run { remember(this) { InspectorBar.ButtonScope(parentScope = this) } }, visible = { true }, enterTransition = { EnterTransition.None }, exitTransition = { ExitTransition.None }, // default value is { it() } decoration = { Surface(color = MaterialTheme.colorScheme.background) { it() } }, onClick = { editorContext.eventHandler.send(EditorEvent.Sheet.Open(SheetType.Volume())) }, // default value is null icon = { Icon( imageVector = IconPack.Music, contentDescription = null, ) }, // default value is null text = { Text( text = "Hello World", ) }, enabled = { true },)
Required and optional parameters:
-
id
- the id of the button. Note that it is highly recommended that every uniqueEditorComponent
has a unique id. Parameter does not have a default value. -
scope
- the scope of this component. Every new value will trigger recomposition of all the lambda parameters below. If you need to accessEditorScope
to construct the scope, useLocalEditorScope
. Consider using ComposeState
objects in the lambda parameters below for granular recompositions over updating the scope, since scope change triggers full recomposition of the button. Ideally, scope should be updated when the parent scope (scope of the parent componentInspectorBar
-InspectorBar.Scope
) is updated and when you want to observe changes from theEngine
. By default the scope is updated only when the parent component scope (InspectorBar.scope
, accessed viaLocalEditorScope
) is updated. -
visible
- whether the button should be visible. Default value is always true. -
enterTransition
- transition of the button when it enters the parent composable. Default value is always no enter transition. -
exitTransition
- transition of the button when it exits the parent composable. Default value is always no exit transition. -
decoration
- decoration of the button. Useful when you want to add custom background, foreground, shadow, paddings etc. Default value is always no decoration. -
onClick
- the callback that is invoked when the button is clicked. Parameter does not have a default value. -
icon
- the icon content of the button. If null, it will not be rendered. Default value is null. -
text
- the text content of the button. If null, it will not be rendered. Default value is null. -
tint
- the tint color of the content. If null, then no tint is applied. Default value is null. -
enabled
- whether the button is enabled. Default value is always true.
Other than the main InspectorBar.Button.remember
function, there is one more convenience overload that has three differences:
icon
is replaced withvectorIcon
lambda, that returnsVectorIcon
instead of drawing the icon content.text
is replaced withtext
lambda, that returnsString
instead of drawing the text content.- An extra parameter
contentDescription
is added that is used by accessibility services to describe what the button does. Note that it is not required to provide value whentext
is not null, since its value will be used by accessibility services, however having bothtext
andcontentDescription
as null will cause a crash.
Create Custom Items#
For completely custom implementations, use InspectorBar.Custom
to render arbitrary content:
@Composablefun rememberInspectorBarCustomItem() = InspectorBar.Custom.remember( id = EditorComponentId("my.package.inspectorBar.newCustomItem"), scope = LocalEditorScope.current.run { remember(this) { InspectorBar.ItemScope(parentScope = this) } }, visible = { true }, enterTransition = { EnterTransition.None }, exitTransition = { ExitTransition.None },) { Box( modifier = Modifier .fillMaxHeight() .clickable { Toast .makeText(editorContext.activity, "Hello World Clicked!", Toast.LENGTH_SHORT) .show() }, ) { Text( modifier = Modifier.align(Alignment.Center), text = "Hello World", ) }}
Required and optional parameters:
-
id
- the id of the custom item. Note that it is highly recommended that every uniqueEditorComponent
has a unique id. Parameter does not have a default value. -
scope
- the scope of this component. Every new value will trigger recomposition of all the lambda parameters below. If you need to accessEditorScope
to construct the scope, useLocalEditorScope
. Consider using ComposeState
objects in the lambda parameters below for granular recompositions over updating the scope, since scope change triggers full recomposition of the custom item. Ideally, scope should be updated when the parent scope (scope of the parent componentInspectorBar
-InspectorBar.Scope
) is updated and when you want to observe changes from theEngine
. Parameter does not have a default value. -
visible
- whether the custom item should be visible. Default value is always true. -
enterTransition
- transition of the custom item when it enters the parent composable. Default value is always no enter transition. -
exitTransition
- transition of the custom item when it exits the parent composable. Default value is always no exit transition. -
content
- the content of the custom item. You are responsible for drawing it, handling clicks etc. Parameter does not have a default value.
List of Available InspectorBar.Buttons#
As you often saw in the previous sections, there are composable functions that look like this: InspectorBar.Button.remember{name}
. All these functions return an InspectorBar.Button
, they are public and can be used in your application. Note that all the parameters of these functions have default values, therefore, you do not need to provide any values, however, if you want to modify any of the parameters, it is exactly the same as described in Create New Buttons section.
Button | ID | Description | Renders For |
---|---|---|---|
InspectorBar.Button.rememberReplace | InspectorBar.Button.Id.replace | Opens library sheet via EditorEvent.Sheet.Open . By default, DesignBlockType , FillType and kind of the selected design block are used to find the library in the Asset Library. Selected asset will replace the content of the currently selected design block. | Video, Image, Sticker, Audio |
InspectorBar.Button.rememberEditText | InspectorBar.Button.Id.editText | Enters text editing mode for the selected design block. | Text |
InspectorBar.Button.rememberFormatText | InspectorBar.Button.Id.formatText | Opens format text sheet via EditorEvent.Sheet.Open . | Text |
InspectorBar.Button.rememberFillStroke | InspectorBar.Button.Id.fillStroke | Opens fill & stroke sheet via EditorEvent.Sheet.Open . | Page, Video, Image, Shape, Text |
InspectorBar.Button.rememberTextBackground | InspectorBar.Button.Id.textBackground | Opens text background sheet via EditorEvent.Sheet.Open . | Text |
InspectorBar.Button.rememberEditVoiceover | InspectorBar.Button.Id.editVoiceover | Opens voiceover sheet via EditorEvent.Sheet.Open . | Video, Audio, Voiceover |
InspectorBar.Button.rememberVolume | InspectorBar.Button.Id.volume | Opens volume sheet via EditorEvent.Sheet.Open . | Video, Audio, Voiceover |
InspectorBar.Button.rememberCrop | InspectorBar.Button.Id.crop | Opens crop sheet via EditorEvent.Sheet.Open . | Video, Image |
InspectorBar.Button.rememberAdjustments | InspectorBar.Button.Id.adjustments | Opens adjustments sheet via EditorEvent.Sheet.Open . | Video, Image |
InspectorBar.Button.rememberFilter | InspectorBar.Button.Id.filter | Opens filter sheet via EditorEvent.Sheet.Open . | Video, Image |
InspectorBar.Button.rememberEffect | InspectorBar.Button.Id.effect | Opens effect sheet via EditorEvent.Sheet.Open . | Video, Image |
InspectorBar.Button.rememberBlur | InspectorBar.Button.Id.blur | Opens blur sheet via EditorEvent.Sheet.Open . | Video, Image |
InspectorBar.Button.rememberShape | InspectorBar.Button.Id.shape | Opens shape sheet via EditorEvent.Sheet.Open . | Video, Image, Shape |
InspectorBar.Button.rememberSelectGroup | InspectorBar.Button.Id.selectGroup | Selects the group design block that contains the currently selected design block via EditorEvent.selectGroupForSelection . | Video, Image, Sticker, Shape, Text |
InspectorBar.Button.rememberEnterGroup | InspectorBar.Button.Id.enterGroup | Changes selection from the selected group design block to a design block within that group via EditorEvent.enterGroupForSelection . | Group |
InspectorBar.Button.rememberLayer | InspectorBar.Button.Id.layer | Opens layer sheet via EditorEvent.Sheet.Open . | Video, Image, Sticker, Shape, Text |
InspectorBar.Button.rememberSplit | InspectorBar.Button.Id.split | Splits currently selected design block via EditorEvent.splitSelection in a video scene. | Video, Image, Sticker, Shape, Text, Audio |
InspectorBar.Button.rememberMoveAsClip | InspectorBar.Button.Id.moveAsClip | Moves currently selected design block into the background track as clip via EditorEvent.moveSelectionAsClip . | Video, Image, Sticker, Shape, Text |
InspectorBar.Button.rememberMoveAsOverlay | InspectorBar.Button.Id.moveAsOverlay | Moves currently selected design block from the background track to an overlay via EditorEvent.moveSelectionAsOverlay . | Video, Image, Sticker, Shape, Text |
InspectorBar.Button.rememberReorder | InspectorBar.Button.Id.reorder | Opens reorder sheet via EditorEvent.Sheet.Open . | Video, Image, Sticker, Shape, Text |
InspectorBar.Button.rememberDuplicate | InspectorBar.Button.Id.duplicate | Duplicates currently selected design block via EditorEvent.duplicateSelection . | Video, Image, Sticker, Shape, Text, Audio |
InspectorBar.Button.rememberDelete | InspectorBar.Button.Id.delete | Deletes currently selected design block via EditorEvent.deleteSelection . | Video, Image, Sticker, Shape, Text, Audio, Voiceover |