TopBar provides a top app bar component with support for scroll behaviors including pinned, enter-always, and exit-until-collapsed modes.
Parameters
modifier
Modifier
default:"Modifier"
Modifier to be applied to the top bar
scrollBehavior
TopBarScrollBehavior?
default:"null"
Scroll behavior that defines how the top bar responds to scrolling. Can be pinned, enter-always, or exit-until-collapsed
colors
TopBarColors
default:"TopBarDefaults.topBarColors()"
Colors for the top bar container in default and scrolled states
windowInsets
WindowInsets?
default:"TopBarDefaults.windowInsets"
Window insets for the top bar. Defaults to system bars on top and horizontal sides
content
@Composable () -> Unit
required
Content of the top bar, typically containing title and actions
TopBarColors
containerColor
Color
default:"AppTheme.colors.background"
Background color of the top bar
scrolledContainerColor
Color
default:"AppTheme.colors.background"
Background color when content is scrolled behind the top bar
The top bar remains pinned at the top and doesn’t move:
val scrollBehavior = TopBarDefaults.pinnedScrollBehavior()
TopBar(
scrollBehavior = scrollBehavior
) {
Text("Pinned Top Bar")
}
The top bar scrolls with content and enters the screen when scrolling up:
state
TopBarState
default:"rememberTopBarState()"
State object for managing scroll offsets
canScroll
() -> Boolean
default:"{ true }"
Callback to determine if scrolling is allowed
snapAnimationSpec
AnimationSpec<Float>?
default:"spring(stiffness = Spring.StiffnessMediumLow)"
Animation spec for snapping behavior
flingAnimationSpec
DecayAnimationSpec<Float>?
default:"rememberSplineBasedDecay()"
Animation spec for fling gestures
val scrollBehavior = TopBarDefaults.enterAlwaysScrollBehavior()
TopBar(
scrollBehavior = scrollBehavior
) {
Text("Enter Always Top Bar")
}
The top bar scrolls off screen when scrolling down and appears when scrolling up:
val scrollBehavior = TopBarDefaults.exitUntilCollapsedScrollBehavior()
TopBar(
scrollBehavior = scrollBehavior
) {
Text("Collapsing Top Bar")
}
Usage Examples
Basic Top Bar
TopBar {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
IconButton(onClick = { /* Menu */ }) {
Icon(Icons.Default.Menu, contentDescription = "Menu")
}
Text(
text = "My App",
style = AppTheme.typography.h2
)
IconButton(onClick = { /* Settings */ }) {
Icon(Icons.Default.Settings, contentDescription = "Settings")
}
}
}
Top Bar with Pinned Behavior
val scrollBehavior = TopBarDefaults.pinnedScrollBehavior()
Scaffold(
topBar = {
TopBar(scrollBehavior = scrollBehavior) {
Text(
text = "Pinned Header",
modifier = Modifier.padding(16.dp),
style = AppTheme.typography.h2
)
}
}
) { paddingValues ->
LazyColumn(
modifier = Modifier
.padding(paddingValues)
.fillMaxSize()
) {
items(100) {
Text("Item $it", modifier = Modifier.padding(16.dp))
}
}
}
Top Bar with Enter Always Behavior
val scrollBehavior = TopBarDefaults.enterAlwaysScrollBehavior()
val lazyListState = rememberLazyListState()
Scaffold(
topBar = {
TopBar(scrollBehavior = scrollBehavior) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
) {
Text(
text = "Scrolling Header",
style = AppTheme.typography.h2
)
}
}
}
) { paddingValues ->
LazyColumn(
state = lazyListState,
modifier = Modifier
.padding(paddingValues)
.nestedScroll(scrollBehavior.nestedScrollConnection)
) {
items(100) {
ListItem(
headlineContent = { Text("Item $it") }
)
HorizontalDivider()
}
}
}
Top Bar with Exit Until Collapsed
val scrollBehavior = TopBarDefaults.exitUntilCollapsedScrollBehavior()
Scaffold(
topBar = {
TopBar(scrollBehavior = scrollBehavior) {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Collapsing Header",
style = AppTheme.typography.h1
)
Text(
text = "Subtitle",
style = AppTheme.typography.body2
)
}
}
}
) { paddingValues ->
LazyColumn(
modifier = Modifier
.padding(paddingValues)
.nestedScroll(scrollBehavior.nestedScrollConnection)
) {
items(50) {
Text(
text = "Content $it",
modifier = Modifier.padding(16.dp)
)
}
}
}
Top Bar with Custom Colors
TopBar(
colors = TopBarDefaults.topBarColors(
containerColor = AppTheme.colors.primary,
scrolledContainerColor = AppTheme.colors.primaryVariant
)
) {
Text(
text = "Custom Colors",
color = AppTheme.colors.onPrimary,
modifier = Modifier.padding(16.dp)
)
}
Top Bar with Actions
TopBar {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Row(verticalAlignment = Alignment.CenterVertically) {
IconButton(onClick = { /* Back */ }) {
Icon(Icons.Default.ArrowBack, "Back")
}
Text(
text = "Detail Page",
style = AppTheme.typography.h2
)
}
Row {
IconButton(onClick = { /* Share */ }) {
Icon(Icons.Default.Share, "Share")
}
IconButton(onClick = { /* More */ }) {
Icon(Icons.Default.MoreVert, "More")
}
}
}
}
TopBarState
State object for managing scroll behavior:
val topBarState = rememberTopBarState(
initialHeightOffsetLimit = -Float.MAX_VALUE,
initialHeightOffset = 0f,
initialContentOffset = 0f
)
val scrollBehavior = TopBarDefaults.enterAlwaysScrollBehavior(
state = topBarState
)
TopBarState Properties
heightOffsetLimit: Float: Maximum offset the bar can collapse
heightOffset: Float: Current offset of the bar
contentOffset: Float: Offset of the content
collapsedFraction: Float: 0f (fully expanded) to 1f (fully collapsed)
overlappedFraction: Float: Fraction of content overlapping the bar
Advanced Examples
Top Bar with Search
var searchExpanded by remember { mutableStateOf(false) }
var searchQuery by remember { mutableStateOf("") }
TopBar {
if (searchExpanded) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
IconButton(onClick = { searchExpanded = false }) {
Icon(Icons.Default.ArrowBack, "Close search")
}
TextField(
value = searchQuery,
onValueChange = { searchQuery = it },
placeholder = { Text("Search...") },
modifier = Modifier.weight(1f)
)
}
} else {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text("My App")
IconButton(onClick = { searchExpanded = true }) {
Icon(Icons.Default.Search, "Search")
}
}
}
}
Top Bar with Color Transition
val scrollBehavior = TopBarDefaults.enterAlwaysScrollBehavior()
val fraction = scrollBehavior.state.overlappedFraction
TopBar(
scrollBehavior = scrollBehavior,
colors = TopBarDefaults.topBarColors(
containerColor = Color.Transparent,
scrolledContainerColor = AppTheme.colors.surface
)
) {
Text(
text = "Color Transition",
modifier = Modifier.padding(16.dp),
color = lerp(
AppTheme.colors.onBackground,
AppTheme.colors.onSurface,
fraction
)
)
}
Constants
- Height: 56dp (TopBarDefaults.TopBarHeight)
- Animation Stiffness: Spring.StiffnessMediumLow
Features
- Scroll Behaviors: Three built-in scroll behaviors
- Smooth Animations: Color and position transitions
- Window Insets: Automatic handling of system bars
- State Management: Saveable state across configuration changes
- Drag Support: Manual dragging when not pinned
- Nested Scroll: Integration with Compose nested scroll system
- Accessibility: Proper traversal group semantics
Best Practices
- Connect scroll behavior: Use
nestedScroll(scrollBehavior.nestedScrollConnection) on scrollable content
- Respect window insets: Use default window insets for proper edge-to-edge display
- Color contrast: Ensure text remains readable during color transitions
- Action placement: Put primary actions on the right, navigation on the left
Source Reference
TopBar component implementation: components-lab/src/commonMain/kotlin/com/nomanr/lumo/ui/components/topbar/TopBar.kt