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

NutrientTabBar is the composable document tab bar. It’s the row of tabs that PdfActivity shows above the document when a DocumentCoordinator has several documents open. The bar comes in two forms. When bound to a DocumentCoordinator, it mirrors the coordinator’s documents, and it switches, closes, and reorders them when the user taps or drags. When driven by a host-supplied list of tabs, it’s a plain tab bar that reports what the user did.

The bar follows the same conventions as NutrientMainToolbar. It takes theme colors with a TabBarColors override, dimensions in a defaults object, and a slot for the content a host replaces.

Basic usage

DocumentState publishes the fragment’s DocumentCoordinator once the UI is ready. Bind the bar to it, and hide the SDK’s own tab bar. Otherwise, both bars show:

val configuration = PdfActivityConfiguration.Builder(context)
.setTabBarHidingMode(TabBarHidingMode.HIDE)
.build()
val documentState = rememberDocumentState(uri, configuration)
val documentCoordinator by documentState.documentCoordinator.collectAsState()
Box(Modifier.fillMaxSize()) {
DocumentView(documentState = documentState, modifier = Modifier.fillMaxSize())
documentCoordinator?.let {
NutrientTabBar(documentCoordinator = it, modifier = Modifier.align(Alignment.TopCenter))
}
}

Add documents to the coordinator with addDocument, as before. The bar mirrors the coordinator. A tap on a tab calls setVisibleDocument, and a tap on a close button calls removeDocument. The Catalog app’s DocumentTabsComposeExample puts a floating-pill main toolbar and this bar above a DocumentView.

The bound bar doesn’t hide itself in immersive mode. Tie its visibility to the rest of the host’s chrome. The example observes toolbarCoordinator.frame.isVisible and animates the main toolbar and the tab bar out together.

Driving the bar from your own tabs

The stateless overload suits a bar that isn’t backed by a DocumentCoordinator. It takes the tabs as input and reports what the user did:

var tabs by remember {
mutableStateOf(listOf(NutrientTabBarTab(id = 1L, title = "Report"), NutrientTabBarTab(id = 2L, title = "Invoice")))
}
var selectedId by remember { mutableStateOf<Long?>(1L) }
NutrientTabBar(
tabs = tabs,
selectedTabId = selectedId,
onTabClick = { selectedId = it.id },
onCloseClick = { tab -> tabs = tabs - tab },
onTabMove = { from, to -> tabs = tabs.toMutableList().apply { add(to, removeAt(from)) }; true },
)

NutrientTabBarTab.id must be unique within the bar and stay the same across reorders and title changes, because the bar animates and drags tabs by it. The bar calls onTabMove live during a long-press drag, and the callback returns whether the host applied the move. Passing null disables drag-to-reorder.

Close mode

closeMode decides which tabs show a close button. It takes the same PdfTabBarCloseMode values as the View bar: CLOSE_ONLY_SELECTED_TAB (the default), CLOSE_ENABLED for every tab, or CLOSE_DISABLED.

Theming

The bar’s colors are a TabBarColors. The surrounding NutrientTheme provides them as UiTheme.colors.tabBar. Inside an SDK-themed context, the SDK reads them from the pspdf__tabBarStyle XML attributes, so an existing theme carries over. Override the colors per bar, or build a TabBarColors from a MaterialTheme with getTabBarColors:

NutrientTabBar(
documentCoordinator = coordinator,
colors = getTabBarColors(
backgroundColor = Color.Transparent,
tabColor = MaterialTheme.colorScheme.surface,
selectedTabColor = MaterialTheme.colorScheme.primary,
selectedTextColor = MaterialTheme.colorScheme.onPrimary,
),
dimensions = NutrientTabBarDefaults.dimensions(height = 52.dp, tabMinWidth = 96.dp),
tabShape = RoundedCornerShape(28.dp),
tabSpacing = 8.dp,
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp),
)
  • TabBarColors — backgroundColor behind the tabs, tabColor for unselected tabs, and selectedTabColor for the selected tab. selectedTabColor also colors the thin separator between touching tabs. textColor and selectedTextColor cover the text. iconColor and selectedIconColor cover the close button and default to the text colors. TabBarColors.from(mainToolbarColors) derives colors that blend the bar with a main toolbar, and UiColorScheme.tabBar defaults to the same derivation.
  • NutrientTabBarDefaults.dimensions() — height, tabMinWidth, textSize, separatorWidth, tabHorizontalPadding, and closeButtonPadding, each defaulting to the value the SDK bar uses.
  • tabShape, tabSpacing, and contentPadding — Set the tab shape, the gap between tabs, and the padding around the row. A non-zero tabSpacing replaces the separator.
  • windowInsets defaults to the horizontal safe-drawing insets, like Material’s app bars. The background extends into the insets, and the tabs stay clear of them. Pass WindowInsets(0, 0, 0, 0) when the host layout already handles the insets.

Custom tab content

tabContent replaces the inside of every tab. The bar still draws the background, shape, selection, separator, ripple, and drag handling. The slot receives a NutrientTabBarTabScope that exposes the tab, isSelected, isCloseable, the bar’s colors and dimensions, and closeTab(). Calling closeTab() does nothing for a tab that the close mode doesn’t make closeable.

To change only the close button, keep the stock content and pass a closeButton. NutrientTabBarDefaults.CloseButton keeps the stock button’s tap handling, ripple, and accessibility semantics, and it accepts a custom icon, tint, size, and padding:

NutrientTabBar(
documentCoordinator = coordinator,
tabContent = {
NutrientTabBarDefaults.TabContent(
this,
closeButton = {
NutrientTabBarDefaults.CloseButton(
this,
painter = rememberVectorPainter(Icons.Rounded.Cancel),
tint = if (isSelected) colors.selectedIconColor else colors.iconColor,
modifier = Modifier.padding(end = 8.dp),
)
},
)
},
)

The bar sizes its tabs for the stock 24dp button plus closeButtonPadding. If a host uses a much larger button, it should also increase tabMinWidth.

API

These are the signatures of the two NutrientTabBar overloads: one bound to a DocumentCoordinator, and one driven by a list of tabs. The table after them describes each parameter and its default:

@Composable
fun NutrientTabBar(
documentCoordinator: DocumentCoordinator,
modifier: Modifier = Modifier,
closeMode: PdfTabBarCloseMode = PdfTabBarCloseMode.CLOSE_ONLY_SELECTED_TAB,
colors: TabBarColors = UiTheme.colors.tabBar,
dimensions: NutrientTabBarDimensions = NutrientTabBarDefaults.dimensions(),
tabShape: Shape = NutrientTabBarDefaults.TabShape,
tabSpacing: Dp = NutrientTabBarDefaults.TabSpacing,
contentPadding: PaddingValues = NutrientTabBarDefaults.ContentPadding,
windowInsets: WindowInsets = NutrientTabBarDefaults.windowInsets,
listState: LazyListState = rememberLazyListState(),
tabContent: @Composable NutrientTabBarTabScope.() -> Unit = { NutrientTabBarDefaults.TabContent(this) },
)
@Composable
fun NutrientTabBar(
tabs: List<NutrientTabBarTab>,
selectedTabId: Long?,
onTabClick: (NutrientTabBarTab) -> Unit,
onCloseClick: (NutrientTabBarTab) -> Unit,
modifier: Modifier = Modifier,
closeMode: PdfTabBarCloseMode = PdfTabBarCloseMode.CLOSE_ONLY_SELECTED_TAB,
colors: TabBarColors = UiTheme.colors.tabBar,
dimensions: NutrientTabBarDimensions = NutrientTabBarDefaults.dimensions(),
tabShape: Shape = NutrientTabBarDefaults.TabShape,
tabSpacing: Dp = NutrientTabBarDefaults.TabSpacing,
contentPadding: PaddingValues = NutrientTabBarDefaults.ContentPadding,
windowInsets: WindowInsets = NutrientTabBarDefaults.windowInsets,
onTabMove: ((fromIndex: Int, toIndex: Int) -> Boolean)? = null,
listState: LazyListState = rememberLazyListState(),
tabContent: @Composable NutrientTabBarTabScope.() -> Unit = { NutrientTabBarDefaults.TabContent(this) },
)
ParameterDefaultWhat it does
documentCoordinator / tabsThe coordinator to mirror, or the tabs to show.
selectedTabId, onTabClick, onCloseClickStateless overload: the selection and the user’s taps.
onTabMovenullStateless overload: live reorder during a drag; null disables dragging.
closeModeCLOSE_ONLY_SELECTED_TABWhich tabs show a close button.
colorsUiTheme.colors.tabBarTabBarColors for background, tabs, text, and close icons.
dimensionsdimensions()Height, minimum tab width, text size, separator, paddings.
tabShape, tabSpacingrectangle, 0.dpTab shape and gap between tabs; a gap replaces the separator.
contentPaddingnonePadding around the row of tabs, inside the background.
windowInsetshorizontal safe drawingInsets the background extends into and the tabs stay clear of.
listStaterememberLazyListState()The row’s scroll state, for scrolling a tab into view.
tabContentNutrientTabBarDefaults.TabContent(this)Slot for the inside of every tab.
  • Multiple documents — DocumentCoordinator, PdfActivity’s tab bar, and TabBarHidingMode.
  • Main toolbar and toolbar hosting — The toolbar the tab bar usually sits under.
  • Catalog app — DocumentTabsComposeExample, DocumentTabsExample.