This HTML page is not optimized for LLM or AI agent consumption. Fetch the Markdown version instead: /guides/android/jetpack-compose/components/contextual-toolbar.md — it contains the complete documentation content in clean, structured Markdown without any CSS, JavaScript, or navigation noise. Jetpack Compose contextual toolbar for PDF viewer | Nutrient Android SDK

NutrientContextualToolbar renders the contextual toolbar that’s currently shown: the annotation creation toolbar, the document editing toolbar, or the content editing toolbar. One composable covers all three because they share the same structure. Each bar has a close button, a row of grouped items with submenus, and a drag handle. The bar docks at the top of the window or at one of its sides. Like the main toolbar, it takes a slot for the close button, which a host can replace, and plain parameters for the chrome. The defaults for both live in NutrientContextualToolbarDefaults.

The bar reads its state from the ToolbarCoordinator. On every mode change, the SDK writes the bar’s kind, items, dock, and draggability to coordinator.contextualToolbar. It does this whether or not the SDK renders the bar itself.

Basic usage

Turn off the SDK’s own contextual toolbar and compose the bar over the document. The composable shows itself when the user enters a mode and hides when the user leaves it. While no bar is shown, it draws nothing:

val configuration = PdfActivityConfiguration.Builder(context)
.defaultToolbarEnabled(false)
.defaultContextualToolbarEnabled(false)
.build()
val documentState = rememberDocumentState(uri, configuration)
val coordinator by documentState.toolbarCoordinator.collectAsState()
Box(Modifier.fillMaxSize()) {
DocumentView(documentState = documentState, modifier = Modifier.fillMaxSize())
coordinator?.let { c ->
NutrientMainToolbar(coordinator = c, modifier = Modifier.fillMaxWidth())
NutrientContextualToolbar(coordinator = c, modifier = Modifier.align(Alignment.TopCenter).fillMaxWidth())
}
}

defaultContextualToolbarEnabled(false) works independently of defaultToolbarEnabled(false). You can keep the SDK’s main toolbar and render only the contextual bar yourself, or do the reverse. When the SDK’s contextual toolbar is disabled, PdfActivity also stops insetting the document for a bar it no longer draws.

Items, clicks, and grouping

The composable doesn’t take items, click handlers, or grouping as parameters. Instead, change the bar’s items with coordinator.updateContextualItems, and react to taps with coordinator.addActionListener. Intercept taps before the SDK handles them with addActionInterceptor, and control grouping with setContextualToolbarGroupingProvider. The contextual toolbars guide covers each of these. Its instructions work unchanged for a bar that the host renders, because both bars read the same coordinator. When no grouping provider is registered on the coordinator, defaultGroupingProvider on the composable supplies a grouping other than the SDK’s presets.

The close button slot

closeButton is the first item in the bar. Its default is NutrientContextualToolbarCloseButton(). The slot runs inside a NutrientContextualToolbarScope, which exposes the bar’s state and a dispatch function. dispatch tags each action with this bar’s kind:

NutrientContextualToolbar(
coordinator = c,
closeButton = {
IconButton(onClick = { dispatch(ToolbarAction.ItemClicked(R.id.pspdf__toolbar_close_button)) }) {
Icon(Icons.Rounded.Close, contentDescription = "Done", tint = UiTheme.colors.mainToolbar.iconColor)
}
},
)

The stock button dispatches ItemClicked with R.id.pspdf__toolbar_close_button, and the SDK leaves the mode in response. The slot can read state.position to see which dock the bar is in for a button that should look different on a side dock.

Shapes for two docks

The bar looks different at the top than at a side, so it takes two shape and border pairs. shape and border apply when the bar is docked at the top. sideDockedShape and sideDockedBorder apply when it’s docked at the start or end edge, where it renders as a vertical rail:

NutrientContextualToolbar(
coordinator = c,
modifier = Modifier.align(Alignment.BottomCenter).padding(16.dp),
shape = RoundedCornerShape(28.dp),
sideDockedShape = RoundedCornerShape(28.dp),
shadowElevation = 8.dp,
colors = NutrientContextualToolbarDefaults.colors().copy(
backgroundColor = MaterialTheme.colorScheme.primaryContainer,
textColor = MaterialTheme.colorScheme.onPrimaryContainer,
),
itemIndication = ToolbarItemIndication(shape = CircleShape),
)

colors is a MainToolbarColors, the same type the main toolbar uses. The bar applies it to the SDK’s buttons, the submenu sheet, and a custom close button. The default reads the pspdf__contextualToolbarStyle theme attributes through the surrounding NutrientTheme.

Width and layout

A top-docked bar is only as wide as its items unless the modifier sets a width. With Modifier.fillMaxWidth(), the bar becomes the edge-to-edge strip that PdfActivity shows. With no width modifier, it renders as a pill. A side-docked bar is always NutrientContextualToolbarDefaults.ToolbarSize thick (58dp) and as tall as its items.

Along its main axis, the bar lays out the close button first, then the grouped items, then the drag handle. The bar divides its available length into 48dp slots to decide how many items fit, and it passes that capacity to the grouping provider. A narrower bar therefore folds more items into submenus. Long-pressing a group slides out its submenu sheet on the document side of the bar. The composable reserves a 58dp strip on that side for the sheet.

The bar reserves windowInsets inside its surface, so its background extends behind the insets. The default is no insets, because NutrientToolbarScaffold and the SDK’s own mount already place the bar inside them. If a host places the bar edge to edge itself, it should pass WindowInsets.statusBars or a similar value.

Docking and dragging

The composable renders where the host places it, using the dock that coordinator.contextualToolbar.value.position reports. Moving the bar between docks is the host’s job:

  • Pass a dragListener to show the drag handle. The NutrientContextualToolbarDragListener receives onDragStarted(), onDragged(deltaX, deltaY), and onDragEnded(). The host moves the bar during the drag. On release, it calls coordinator.setContextualToolbarPosition(...) with the dock the bar landed on. A bar that doesn’t support docking passes no listener and shows no handle.
  • effectivePosition overrides the dock the bar lays out for. Use it when the host can’t honor the position in the state — for example, when a vertical bar doesn’t fit.
  • verticalDockAvailable tells the bar whether a drag may end on a side dock. When it returns false, the bar offers only the top dock while dragging.

To get the same docking chrome as PdfActivity, place the bar through NutrientToolbarScaffold or NutrientToolbars instead of positioning it yourself. That chrome includes drop zones and dock slots. The scaffold supplies effectivePosition and dragListener through its ContextualToolbarSlotScope.

API

This is the full signature of NutrientContextualToolbar. The table after it describes each parameter and its default:

@Composable
fun NutrientContextualToolbar(
coordinator: ToolbarCoordinator,
modifier: Modifier = Modifier,
defaultGroupingProvider: ContextualToolbarGroupingProvider? = null,
dragListener: NutrientContextualToolbarDragListener? = null,
verticalDockAvailable: () -> Boolean = { true },
effectivePosition: ToolbarPosition? = null,
closeButton: @Composable NutrientContextualToolbarScope.() -> Unit = { NutrientContextualToolbarCloseButton() },
shape: Shape = NutrientContextualToolbarDefaults.Shape,
border: BorderStroke? = null,
sideDockedShape: Shape = NutrientContextualToolbarDefaults.SideDockedShape,
sideDockedBorder: BorderStroke? = NutrientContextualToolbarDefaults.sideDockedBorder(),
shadowElevation: Dp = NutrientContextualToolbarDefaults.shadowElevation,
windowInsets: WindowInsets = NutrientContextualToolbarDefaults.NoWindowInsets,
colors: MainToolbarColors = NutrientContextualToolbarDefaults.colors(),
itemIndication: ToolbarItemIndication = NutrientContextualToolbarDefaults.ItemIndication,
enter: EnterTransition = NutrientContextualToolbarDefaults.enterTransition,
exit: ExitTransition = NutrientContextualToolbarDefaults.exitTransition,
)
ParameterDefaultWhat it does
coordinatorThe ToolbarCoordinator whose contextualToolbar state the bar renders.
modifierModifierPlacement and width of the bar.
defaultGroupingProvidernullGrouping used when none is registered on the coordinator; null keeps the SDK presets.
dragListenernullReceives drag gestures from the handle; null hides the handle.
verticalDockAvailable{ true }Whether a drag may end on a side dock; false offers only the top dock.
effectivePositionnullDock to lay out for when it differs from the state’s position.
closeButtonNutrientContextualToolbarCloseButton()Leading slot in NutrientContextualToolbarScope (state, dispatch).
shape, borderRectangleShape, nullChrome when docked at the top.
sideDockedShape, sideDockedBorder16dp rounded, 1dp themed borderChrome when docked at a side.
shadowElevationthemedElevation of the surface.
windowInsetsNoWindowInsetsInsets reserved inside the surface.
colorscolors()MainToolbarColors for the bar, its items, and the submenu sheet.
itemIndicationItemIndicationShape and ripple of item states.
enter, exitfade in, fade outTransitions when a bar appears or disappears.

NutrientContextualToolbarDefaults also exposes ToolbarSize, toolbarSize(context) (the themed pspdf__contextualToolbarHeight), VerticalMargin, HorizontalMargin, DropZoneCornerRadius, dragTargetColor(context), and statusBarColor(context) for hosts that build their own docking chrome.

Behavior

  • Long-pressing an icon-only item shows a tooltip on the document side of the bar. Long-pressing a group opens its submenu.
  • The bar’s surface is tagged pspdf__contextual_toolbar. Each item carries its resource entry name as a test tag — for example, pspdf__annotation_toolbar_item_undo.
  • The bar supports right-to-left layouts: ToolbarPosition.Start is the right edge there.
  • Contextual toolbars — Items, clicks, grouping, and docking through the coordinator.
  • Toolbar hosting — NutrientToolbars and NutrientToolbarScaffold, which place this bar with the SDK’s docking chrome.
  • Floating toolbars — NutrientFloatingContextualToolbar, the same bar as a floating pill.
  • Catalog app — CustomToolbarsDocumentViewExample, CustomToolbarsPdfActivityExample.