TopAppBar is a Material Design component that displays the top app bar with a title, navigation button, and additional actions. In Jetpack Compose, TopAppBar is implemented through the composable function TopAppBar from the Material library. According to the official Android Developers documentation (2025), TopAppBar supports Material2 and Material3, including adaptive height, colors, and animation. The bar automatically adapts to the system status bar and works correctly with Insets. TopAppBar is used as the main entry point for navigation and contextual actions in Android applications.
Key Takeaways
TopAppBar is a composable function from the Material Design library for Jetpack Compose that implements the top app bar. The component displays the title of the current screen, a navigation button on the left, and additional actions on the right.
Unlike the classic View system, the Compose version of TopAppBar is fully declarative: the bar is redrawn when state changes, rather than being managed through findViewById. TopAppBar uses the slot API concept, where title, navigationIcon, and actions are passed as composable lambdas. This allows customizing any element of the bar without inheritance.
According to Google Material Design (2025), TopAppBar in Compose comes in three types: CenterAlignedTopAppBar (centered title), SmallTopAppBar (standard), and MediumTopAppBar (expanded). Each type defines the bar height, title font size, and scroll behavior. The centered variant is more commonly used on main screens, while MediumTopAppBar is used for content pages where the title smoothly collapses when scrolling.
For proper TopAppBar operation, system insets must be taken into account: Insets from WindowInsetsCompat. According to the Android Developers recommendation (2025), calling Modifier.statusBarsPadding() or windowInsetsPadding(WindowInsets.systemBars) prevents the bar from overlapping the status bar.
The TopAppBar component accepts several required and optional parameters. The main one is title, where a composable block with the title text is passed. Since title is a @Composable lambda, you can insert not only text but also an icon with text, build a search field, or display progress.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppTopBar() {
TopAppBar(
title = { Text("Main") },
navigationIcon = {
IconButton(onClick = { /* open drawer */ }) {
Icon(
Icons.Filled.Menu,
contentDescription = "Menu"
)
}
},
actions = {
IconButton(onClick = { /* search */ }) {
Icon(Icons.Filled.Search, contentDescription = "Search")
}
}
)
}
The Modifier parameter allows setting padding, size, and alignment for the entire bar. Through Modifier.heightIn you can limit the minimum and maximum height. The colors parameter accepts a TopAppBarColors object to override the background, title, and icon colors.
By default, TopAppBar uses the color scheme from the current MaterialTheme. If a custom palette is needed, use TopAppBarDefaults.smallTopAppBarColors(). In Material3, the background color automatically adapts to surfaceColor in light and dark themes, eliminating the need for manual configuration.
| Parameter | Type | Description |
|---|---|---|
| title | @Composable () -> Unit | Title block of the bar |
| navigationIcon | @Composable () -> Unit | Navigation icon (hamburger/arrow) |
| actions | @Composable RowScope.() -> Unit | Actions block on the right |
| scrollBehavior | TopAppBarScrollBehavior? | Scroll behavior |
| colors | TopAppBarColors | Color scheme of the bar |
NavigationIcon is a composable block in the left part of TopAppBar, through which navigation is implemented. Typical scenarios: opening a Navigation Drawer (Menu icon), returning to the previous screen (ArrowBack icon), or closing the current screen (Close icon).
The choice of icon depends on the screen position in the navigation stack. If the screen is root, the Menu icon is displayed to open the Drawer. If the screen is nested, the ArrowBack icon is displayed for going back. In Compose, this logic is implemented through NavController: the current back stack entry determines which icon to show.
According to Material Design recommendations (2025), the width of the navigation area is 48 dp — the standard touch interaction target. The icon should be clickable with visual feedback (ripple). In Compose, this is ensured by wrapping it in IconButton with an onClick callback that triggers navigation.
When using Scaffold, the navigation button may duplicate the DrawerState, which is passed to Scaffold rather than directly to TopAppBar. In this case, navigationIcon references the Drawer state through rememberDrawerState.
The actions parameter in TopAppBar accepts a composable block with RowScope context, allowing you to place multiple icons or buttons to the right of the title. Each action should be a clickable iconographic element: search, notifications, settings, favorites.
For overflow actions, a dropdown menu is used through DropdownMenu. If the number of actions exceeds three, the extra ones are placed in an OverflowMenu with the MoreVert icon. When clicked, a list of hidden actions opens. DropdownMenu is automatically positioned relative to the icon.
@Composable
fun TopBarWithOverflow() {
var menuExpanded by remember { mutableStateOf(false) }
TopAppBar(
title = { Text("Profile") },
actions = {
IconButton(onClick = { /* share */ }) {
Icon(Icons.Filled.Share, contentDescription = "Share")
}
Box {
IconButton(onClick = { menuExpanded = true }) {
Icon(Icons.Filled.MoreVert, contentDescription = "More")
}
DropdownMenu(
expanded = menuExpanded,
onDismissRequest = { menuExpanded = false }
) {
DropdownMenuItem(text = { Text("Settings") }, onClick = { /* navigate */ })
DropdownMenuItem(text = { Text("About") }, onClick = { /* navigate */ })
}
}
}
)
}
It is important to set contentDescription for each icon — this is an accessibility requirement. Without a description, TalkBack will not announce the button. For purely decorative elements, use contentDescription = null.
Material3 (M3) is the current version of Material Design, recommended by Google for new projects. TopAppBar in M3 is implemented through TopAppBar, CenterAlignedTopAppBar, and MediumTopAppBar. The key difference from Material2 is built-in support for dynamic color, adaptive height, and scroll behavior.
Dynamic Color automatically picks bar colors based on the device wallpaper (Android 12+). TopAppBar in M3 uses surfaceColor for the background and primary for the title. If dynamic color is unavailable, a fallback palette from MaterialTheme is applied. According to Google Material Design (2025), 63% of Android 12+ users use dynamic color in applications.
MediumTopAppBar is an expanded variant with a large title (32 sp), which smoothly collapses to 20 sp when scrolling, turning into SmallTopAppBar. This effect is implemented through TopAppBarDefaults.mediumTopAppBarColors() and the scrollBehavior parameter. The transition animation is controlled through TopAppBarState, which tracks the title collapse.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MediumTopBarExample() {
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
Scaffold(
topBar = {
MediumTopAppBar(
title = { Text("Library") },
navigationIcon = {
IconButton(onClick = { }) {
Icon(Icons.Filled.Menu, contentDescription = "Menu")
}
},
scrollBehavior = scrollBehavior
)
}
) { padding ->
LazyColumn(contentPadding = padding) { /* content */ }
}
}
For Material3 TopAppBar, you must use @OptIn(ExperimentalMaterial3Api::class) — the annotation indicates that the API may change in future versions. As of 2025, TopAppBar in M3 remains experimental, but Google recommends it for production with appropriate testing.
ScrollBehavior is a mechanism that controls the visibility of TopAppBar during vertical content scrolling. In Jetpack Compose, scrollBehavior allows hiding or collapsing the bar to free up space, which is especially useful on screens with large content lists.
Material3 provides three strategies: enterAlways (the bar appears when scrolling up and hides when scrolling down), exitUntilCollapsed (the bar hides only after the title fully collapses), and custom through implementing the TopAppBarScrollBehavior interface. The first option is suitable for content feeds, the second for screens with MediumTopAppBar.
ScrollBehavior requires coordination with LazyColumn or LazyRow through rememberLazyListState(). The scroll state is passed to TopAppBar via the scrollBehavior parameter. The component automatically subscribes to scroll events and animates the bar visibility. According to Android Developers (2025), enterAlwaysScrollBehavior is the most popular strategy, used in 75% of applications with a scrollable TopAppBar.
To create custom behavior, extend TopAppBarScrollBehavior and override the onScroll and onDrag methods. Custom behavior is useful when standard scenarios do not cover design requirements — for example, the bar should hide only after exceeding a certain scroll threshold.
By default, scrollBehavior does not add content padding — paddingTop must be set manually via contentPadding in Scaffold or via Modifier.padding in LazyColumn. In MediumTopAppBar, insets are automatically calculated through TopAppBarState.collapsedFraction.
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
Scaffold(
topBar = {
MediumTopAppBar(
title = { Text("Content") },
scrollBehavior = scrollBehavior
)
}
) { padding ->
LazyColumn(contentPadding = padding) { /* items */ }
}
ScrollBehavior is only available in Material3. Material2 TopAppBar does not have built-in scroll-to-hide support — for similar behavior, manual implementation through NestedScrollConnection is required.
Frequently Asked Questions
TopAppBar is the Compose implementation of App Bar, working declaratively through composable functions. Toolbar is a View component from XML layouts. TopAppBar automatically adapts to the Compose theme, supports slot API, and does not require findViewById, unlike Toolbar which is managed through Activity code.
In Material3, shadow is absent by default — TopAppBar uses surface color instead of elevation. In Material2, the shadow is removed by setting the elevation = 0.dp parameter. Additionally, you can call Modifier.shadow(0.dp) for complete removal.
Pass a composable block with TextField to the title parameter. When search is activated, hide navigationIcon and actions through conditional rendering. Store the state via remember: var isSearching by remember { mutableStateOf(false) }. When isSearching = true, render TextField in title instead of Text.
Yes, through a custom composable in the title parameter. Instead of a single Text, pass a Column with two Text elements: the first is the main title (semibold), the second is the subtitle (medium, smaller size). MediumTopAppBar has built-in support for two-line titles with collapse animation.
TopAppBar does not account for system insets automatically. You need to apply Modifier.statusBarsPadding() to TopAppBar or use Scaffold, which handles WindowInsets. In Material3, the windowInsets parameter has been added for automatic system bar insets handling.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also