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—backgroundColorbehind the tabs,tabColorfor unselected tabs, andselectedTabColorfor the selected tab.selectedTabColoralso colors the thin separator between touching tabs.textColorandselectedTextColorcover the text.iconColorandselectedIconColorcover the close button and default to the text colors.TabBarColors.from(mainToolbarColors)derives colors that blend the bar with a main toolbar, andUiColorScheme.tabBardefaults to the same derivation.NutrientTabBarDefaults.dimensions()—height,tabMinWidth,textSize,separatorWidth,tabHorizontalPadding, andcloseButtonPadding, each defaulting to the value the SDK bar uses.tabShape,tabSpacing, andcontentPadding— Set the tab shape, the gap between tabs, and the padding around the row. A non-zerotabSpacingreplaces the separator.windowInsetsdefaults to the horizontal safe-drawing insets, like Material’s app bars. The background extends into the insets, and the tabs stay clear of them. PassWindowInsets(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:
@Composablefun 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) },)
@Composablefun 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) },)| Parameter | Default | What it does |
|---|---|---|
documentCoordinator / tabs | The coordinator to mirror, or the tabs to show. | |
selectedTabId, onTabClick, onCloseClick | Stateless overload: the selection and the user’s taps. | |
onTabMove | null | Stateless overload: live reorder during a drag; null disables dragging. |
closeMode | CLOSE_ONLY_SELECTED_TAB | Which tabs show a close button. |
colors | UiTheme.colors.tabBar | TabBarColors for background, tabs, text, and close icons. |
dimensions | dimensions() | Height, minimum tab width, text size, separator, paddings. |
tabShape, tabSpacing | rectangle, 0.dp | Tab shape and gap between tabs; a gap replaces the separator. |
contentPadding | none | Padding around the row of tabs, inside the background. |
windowInsets | horizontal safe drawing | Insets the background extends into and the tabs stay clear of. |
listState | rememberLazyListState() | The row’s scroll state, for scrolling a tab into view. |
tabContent | NutrientTabBarDefaults.TabContent(this) | Slot for the inside of every tab. |
Related
- Multiple documents —
DocumentCoordinator,PdfActivity’s tab bar, andTabBarHidingMode. - Main toolbar and toolbar hosting — The toolbar the tab bar usually sits under.
- Catalog app —
DocumentTabsComposeExample,DocumentTabsExample.