FAB menu and Medium FAB in Compose
The FAB menu replaces the speed dial. The FAB morphs into a close button, and 2 to 6 labelled actions open above it. When it closes, the items fold back into the FAB.
data class FabAction(val icon: ImageVector, val label: String, val onClick: () -> Unit)
@Composablefun ComposeFabMenu( actions: List<FabAction>, addIcon: ImageVector, closeIcon: ImageVector, listState: LazyListState, modifier: Modifier = Modifier,) { var expanded by rememberSaveable { mutableStateOf(false) } BackHandler(expanded) { expanded = false } val fabVisible by remember { derivedStateOf { listState.firstVisibleItemIndex == 0 || !listState.canScrollForward } }
Box(modifier.fillMaxSize()) { FloatingActionButtonMenu( modifier = Modifier.align(Alignment.BottomEnd), expanded = expanded, button = { ToggleFloatingActionButton( checked = expanded, onCheckedChange = { expanded = it }, modifier = Modifier .semantics { traversalIndex = -1f stateDescription = if (expanded) "Expanded" else "Collapsed" contentDescription = "Toggle menu" } .animateFloatingActionButton( visible = fabVisible || expanded, alignment = Alignment.BottomEnd, ), ) { // checkedProgress goes 0 -> 1 as the FAB morphs into the close button. val icon by remember { derivedStateOf { if (checkedProgress > 0.5f) closeIcon else addIcon } } Icon( painter = rememberVectorPainter(icon), contentDescription = null, modifier = Modifier.animateIcon({ checkedProgress }), ) } }, ) { actions.forEach { action -> FloatingActionButtonMenuItem( onClick = { expanded = false; action.onClick() }, icon = { Icon(action.icon, contentDescription = null) }, text = { Text(action.label) }, ) } } }}FAB sizes
Section titled “FAB sizes”| Composable | Size | Corner |
|---|---|---|
FloatingActionButton |
56dp | 16dp (large) |
MediumFloatingActionButton (new) |
80dp | 20dp (largeIncreased) |
LargeFloatingActionButton |
96dp | 28dp (extraLarge) |
@Composablefun NewItemFab(icon: ImageVector, onClick: () -> Unit) { // FAB sizes: FloatingActionButton 56dp, MediumFloatingActionButton 80dp (new in 1.5.0), // LargeFloatingActionButton 96dp. M3 Expressive guidance steers away from the 40dp small FAB. MediumFloatingActionButton(onClick = onClick) { Icon(icon, contentDescription = "New item") }}Accessibility
Section titled “Accessibility”- The toggle FAB comes first in traversal order (
traversalIndex = -1f). - It announces Expanded / Collapsed.
- Back closes the menu.
Google’s sample also wraps the FAB in a TooltipBox and adds a “Close menu” custom action on the
last item.
Common mistakes
Section titled “Common mistakes”- Putting more than 6 actions in the menu. Move extra actions to a sheet.
- Leaving the FAB visible while the list scrolls. Use
Modifier.animateFloatingActionButton(visible = …).
Related: floating toolbar · design rules: morph, don’t swap
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.