DEV Community

myougaTheAxo
myougaTheAxo

Posted on

TopAppBar in Compose: All 4 Variants & Scroll Behavior Guide

TopAppBar in Compose: All 4 Variants & Scroll Behavior Guide

Jetpack Compose Material3 offers four TopAppBar variants with flexible scroll behaviors. Let's master them all.

1. Small TopAppBar (Default)

The most compact variant, perfect for basic app bars.

@Composable
fun SmallTopAppBar(
    title: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    navigationIcon: @Composable () -> Unit = {},
    actions: @Composable RowScope.() -> Unit = {},
    colors: TopAppBarColors = TopAppBarDefaults.smallTopAppBarColors(),
    scrollBehavior: TopAppBarScrollBehavior? = null,
) {}
Enter fullscreen mode Exit fullscreen mode

Example:

TopAppBar(
    title = { Text("My App") },
    navigationIcon = {
        IconButton(onClick = { /* Menu */ }) {
            Icon(Icons.Default.Menu, contentDescription = null)
        }
    },
    actions = {
        IconButton(onClick = { /* Search */ }) {
            Icon(Icons.Default.Search, contentDescription = null)
        }
        IconButton(onClick = { /* More */ }) {
            Icon(Icons.Default.MoreVert, contentDescription = null)
        }
    }
)
Enter fullscreen mode Exit fullscreen mode

2. CenterAligned TopAppBar

Title is centered, useful for detail screens.

@Composable
fun CenterAlignedTopAppBar(
    title: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    navigationIcon: @Composable () -> Unit = {},
    actions: @Composable RowScope.() -> Unit = {},
    colors: TopAppBarColors = TopAppBarDefaults.centerAlignedTopAppBarColors(),
    scrollBehavior: TopAppBarScrollBehavior? = null,
) {}
Enter fullscreen mode Exit fullscreen mode

Example:

CenterAlignedTopAppBar(
    title = { Text("Article Details") },
    navigationIcon = {
        IconButton(onClick = { navController.popBackStack() }) {
            Icon(Icons.Default.ArrowBack, contentDescription = null)
        }
    }
)
Enter fullscreen mode Exit fullscreen mode

3. Medium TopAppBar

Larger title with more breathing room. Collapses on scroll.

MediumTopAppBar(
    title = { Text("Headlines", modifier = Modifier.padding(12.dp)) },
    navigationIcon = {
        IconButton(onClick = { /* Menu */ }) {
            Icon(Icons.Default.Menu, contentDescription = null)
        }
    },
    scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
)
Enter fullscreen mode Exit fullscreen mode

4. Large TopAppBar

Maximum height variant for prominent titles. Great for search or category screens.

LargeTopAppBar(
    title = { Text("Explore", modifier = Modifier.padding(12.dp)) },
    navigationIcon = {
        IconButton(onClick = { /* Menu */ }) {
            Icon(Icons.Default.Menu, contentDescription = null)
        }
    },
    scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
)
Enter fullscreen mode Exit fullscreen mode

Scroll Behaviors

enterAlways

App bar always appears at the top on scroll up.

val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState())

Scaffold(
    topBar = {
        SmallTopAppBar(
            title = { Text("Items") },
            scrollBehavior = scrollBehavior
        )
    },
    modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
) { paddingValues ->
    LazyColumn(
        contentPadding = paddingValues,
        modifier = Modifier.fillMaxSize()
    ) {
        items(100) { index ->
            ListItem(headlineContent = { Text("Item $index") })
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

exitUntilCollapsed

App bar collapses fully before list scrolls.

val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
    rememberTopAppBarState()
)

Scaffold(
    topBar = {
        LargeTopAppBar(
            title = { Text("Categories") },
            scrollBehavior = scrollBehavior
        )
    },
    modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
) { paddingValues ->
    // List content
}
Enter fullscreen mode Exit fullscreen mode

pinned

App bar stays fixed at the top (no scroll collapse).

val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())

Scaffold(
    topBar = {
        SmallTopAppBar(
            title = { Text("Fixed Header") },
            scrollBehavior = scrollBehavior
        )
    },
    modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
) { paddingValues ->
    // Content scrolls behind fixed app bar
}
Enter fullscreen mode Exit fullscreen mode

Custom Colors

val customColors = TopAppBarDefaults.smallTopAppBarColors(
    containerColor = Color.Blue,
    titleContentColor = Color.White,
    navigationIconContentColor = Color.White,
    actionIconContentColor = Color.White,
    scrolledContainerColor = Color.DarkGray
)

TopAppBar(
    title = { Text("Styled App") },
    colors = customColors,
    navigationIcon = { /* ... */ },
    actions = { /* ... */ }
)
Enter fullscreen mode Exit fullscreen mode

Complete Example with NestedScroll

@Composable
fun CompleteAppBarExample() {
    val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
        rememberTopAppBarState()
    )

    Scaffold(
        modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
        topBar = {
            LargeTopAppBar(
                title = {
                    Text(
                        "My Articles",
                        modifier = Modifier
                            .padding(12.dp)
                            .fillMaxWidth(),
                        style = MaterialTheme.typography.headlineSmall
                    )
                },
                navigationIcon = {
                    IconButton(onClick = { /* Menu */ }) {
                        Icon(Icons.Default.Menu, contentDescription = null)
                    }
                },
                actions = {
                    IconButton(onClick = { /* Search */ }) {
                        Icon(Icons.Default.Search, contentDescription = null)
                    }
                },
                scrollBehavior = scrollBehavior
            )
        }
    ) { paddingValues ->
        LazyColumn(
            contentPadding = paddingValues,
            modifier = Modifier.fillMaxSize()
        ) {
            items(50) { index ->
                Card(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(12.dp)
                ) {
                    ListItem(
                        headlineContent = { Text("Article $index") },
                        supportingContent = { Text("Author: John Doe") }
                    )
                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Best Practices

  1. Use Small for most screens - Default choice, minimal overhead
  2. Use CenterAligned for detail pages - Provides focus
  3. Use Medium/Large for exploratory screens - Better visual hierarchy
  4. Always pair with nestedScroll - Required for scroll behaviors to work
  5. Choose scroll behavior wisely:
    • enterAlways - Quick access to app bar
    • exitUntilCollapsed - Better content visibility
    • pinned - Persistent header (search bars)
  6. Provide meaningful navigation icons - Users expect back button on detail screens
  7. Limit action icons - Max 3-4 icons to avoid crowding

Conclusion

Master TopAppBar variants and scroll behaviors to create professional, modern app bar UIs in Jetpack Compose Material3.


8 Android App Templates → https://myougatheax.gumroad.com

Top comments (0)