Floating toolbar in Jetpack Compose
Floating toolbars replace the bottom app bar for contextual actions. In Google’s before/after, a docked bar with a FAB becomes a floating pill toolbar with a separate FAB of a different shape and color.
@Composablefun EditorScreen( lines: List<String>, toolIcons: List<Pair<ImageVector, String>>, addIcon: ImageVector, onAdd: () -> Unit,) { // Floating toolbars replace the bottom app bar in M3 Expressive. They hide on scroll down. val exitAlways = FloatingToolbarDefaults.exitAlwaysScrollBehavior( exitDirection = FloatingToolbarExitDirection.Bottom, ) Scaffold(modifier = Modifier.nestedScroll(exitAlways)) { padding -> Box(Modifier.padding(padding)) { LazyColumn { items(lines) { ListItem { Text(it) } } } HorizontalFloatingToolbar( expanded = true, floatingActionButton = { FloatingToolbarDefaults.VibrantFloatingActionButton(onClick = onAdd) { Icon(addIcon, contentDescription = "Add") } }, colors = FloatingToolbarDefaults.vibrantFloatingToolbarColors(), scrollBehavior = exitAlways, modifier = Modifier .align(Alignment.BottomCenter) .offset(y = -FloatingToolbarDefaults.ScreenOffset) .zIndex(1f), ) { toolIcons.forEach { (icon, label) -> IconButton(onClick = {}) { Icon(icon, contentDescription = label) } } } } }}Colors: vibrantFloatingToolbarColors() (primary container) or standardFloatingToolbarColors()
(surface container). To collapse a toolbar without a FAB to its main content, use the overload
with expanded, leadingContent and trailingContent.
Before / after
Section titled “Before / after”/** * Google's before/after: a docked bottom bar with a FAB becomes a floating toolbar plus a * separate FAB in a contrasting shape and color. The FAB is the primary action, so it gets the * vibrant container and the square-ish shape; the toolbar stays a pill. */@Composablefun ComposeActions(actions: List<Pair<ImageVector, String>>, primary: ImageVector, onPrimary: () -> Unit) { HorizontalFloatingToolbar( expanded = true, floatingActionButton = { FloatingToolbarDefaults.VibrantFloatingActionButton(onClick = onPrimary) { Icon(primary, contentDescription = "Compose") } }, ) { actions.forEach { (icon, label) -> IconButton(onClick = {}) { Icon(icon, contentDescription = label) } } }}Common mistakes
Section titled “Common mistakes”- Placing it inside
Scaffold(bottomBar = …). It floats over content: align it bottom-centre in aBox, offset byFloatingToolbarDefaults.ScreenOffset. - Forgetting
Modifier.nestedScroll(exitAlways)on the scrolling parent, which stops it hiding on scroll.
Related: FAB menu · flexible top app bar
Want your agent to get this right every time? Install the skill. If this page helped,star the repo on GitHub.
Built by Sanikant. Set in Google Sans Flex (SIL Open Font License), icons from Material Symbols (Apache 2.0). Material Design is a Google trademark; this project is not affiliated with Google.