---
title: "Jetpack Compose document tab bar for PDF viewer | Nutrient Android SDK"
canonical_url: "https://www.nutrient.io/guides/android/jetpack-compose/components/tab-bar/"
md_url: "https://www.nutrient.io/guides/android/jetpack-compose/components/tab-bar.md"
last_updated: "2026-10-12T10:12:58.189Z"
description: "Show a tab bar for multiple open documents in Jetpack Compose with NutrientTabBar: bound to a DocumentCoordinator or driven by your own tabs, themed with TabBarColors, with custom tab content, and drag-to-reorder."
---

# Tab bar

`NutrientTabBar` is the composable document tab bar. It’s the row of tabs that `PdfActivity` shows above the document when a [`DocumentCoordinator`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.ui/-document-coordinator/index.html) 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`](https://www.nutrient.io/guides/android/jetpack-compose/components/main-toolbar/). 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:

```kotlin

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:

```kotlin

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`](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.compose.theme/-nutrient-theme.html) 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`:

```kotlin

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:

```kotlin

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:

```kotlin

@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) },
)

```

| 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](https://www.nutrient.io/guides/android/features/working-with-multiple-documents.md) — `DocumentCoordinator`, `PdfActivity`’s tab bar, and `TabBarHidingMode`.

- [Main toolbar](https://www.nutrient.io/guides/android/jetpack-compose/components/main-toolbar.md) and [toolbar hosting](https://www.nutrient.io/guides/android/jetpack-compose/components/toolbar-hosting.md) — The toolbar the tab bar usually sits under.

- Catalog app — `DocumentTabsComposeExample`, `DocumentTabsExample`.
---

## Related pages

- [Contextual toolbar](/guides/android/jetpack-compose/components/contextual-toolbar.md)
- [Floating toolbars](/guides/android/jetpack-compose/components/floating-toolbars.md)
- [Main toolbar](/guides/android/jetpack-compose/components/main-toolbar.md)
- [Toolbar hosting](/guides/android/jetpack-compose/components/toolbar-hosting.md)

