VerticalFloatingToolbar

Composable Component

A vertical floating toolbar displays navigation and key actions in a Column. It can be positioned anywhere on the screen and floats over the rest of the content.

Common
@ExperimentalMaterial3ExpressiveApi
@Composable
fun VerticalFloatingToolbar(
    expanded: Boolean,
    modifier: Modifier = Modifier,
    colors: FloatingToolbarColors = FloatingToolbarDefaults.standardFloatingToolbarColors(),
    contentPadding: PaddingValues = FloatingToolbarDefaults.ContentPadding,
    scrollBehavior: FloatingToolbarScrollBehavior? = null,
    shape: Shape = FloatingToolbarDefaults.ContainerShape,
    leadingContent: @Composable (ColumnScope.() -> Unit)? = null,
    trailingContent: @Composable (ColumnScope.() -> Unit)? = null,
    expandedShadowElevation: Dp = FloatingToolbarDefaults.ContainerExpandedElevation,
    collapsedShadowElevation: Dp = FloatingToolbarDefaults.ContainerCollapsedElevation,
    content: @Composable ColumnScope.() -> Unit,
)

Parameters

expandedwhether the FloatingToolbar is in expanded mode, i.e. showing leadingContent and trailingContent. Note that the toolbar will stay expanded in case a touch exploration service (e.g., TalkBack) is active.
modifierthe Modifier to be applied to this FloatingToolbar.
colorsthe colors used for this floating toolbar. There are two predefined FloatingToolbarColors at FloatingToolbarDefaults.standardFloatingToolbarColors and FloatingToolbarDefaults.vibrantFloatingToolbarColors which you can use or modify.
contentPaddingthe padding applied to the content of this FloatingToolbar.
scrollBehaviora FloatingToolbarScrollBehavior. If null, this FloatingToolbar will not automatically react to scrolling. Note that the toolbar will not react to scrolling in case a touch exploration service (e.g., TalkBack) is active.
shapethe shape used for this FloatingToolbar.
leadingContentthe leading content of this FloatingToolbar. The default layout here is a Column, so content inside will be placed vertically. Only showing if expanded is true.
trailingContentthe trailing content of this FloatingToolbar. The default layout here is a Column, so content inside will be placed vertically. Only showing if expanded is true.
expandedShadowElevationthe elevation for the shadow below this floating toolbar when expanded.
collapsedShadowElevationthe elevation for the shadow below this floating toolbar when collapsed.
contentthe main content of this FloatingToolbar. The default layout here is a Column, so content inside will be placed vertically.
Common
@ExperimentalMaterial3ExpressiveApi
@Composable
fun VerticalFloatingToolbar(
    expanded: Boolean,
    floatingActionButton: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    colors: FloatingToolbarColors = FloatingToolbarDefaults.standardFloatingToolbarColors(),
    contentPadding: PaddingValues = FloatingToolbarDefaults.ContentPadding,
    scrollBehavior: FloatingToolbarScrollBehavior? = null,
    shape: Shape = FloatingToolbarDefaults.ContainerShape,
    floatingActionButtonPosition: FloatingToolbarVerticalFabPosition =
        FloatingToolbarVerticalFabPosition.Bottom,
    animationSpec: FiniteAnimationSpec<Float> = FloatingToolbarDefaults.animationSpec(),
    expandedShadowElevation: Dp = FloatingToolbarDefaults.ContainerExpandedElevationWithFab,
    collapsedShadowElevation: Dp = FloatingToolbarDefaults.ContainerCollapsedElevationWithFab,
    content: @Composable ColumnScope.() -> Unit,
)

Parameters

expandedwhether the floating toolbar is expanded or not. In its expanded state, the FAB and the toolbar content are organized vertically. Otherwise, only the FAB is visible. Note that the toolbar will stay expanded in case a touch exploration service (e.g., TalkBack) is active.
floatingActionButtona floating action button to be displayed by the toolbar. It's recommended to use a FloatingToolbarDefaults.VibrantFloatingActionButton or FloatingToolbarDefaults.StandardFloatingActionButton that is styled to match the colors. Note that the provided FAB's size is controlled by the floating toolbar and animates according to its state. In case a custom FAB is provided, make sure it's set with a Modifier.fillMaxSize to be sized correctly.
modifierthe Modifier to be applied to this floating toolbar.
colorsthe colors used for this floating toolbar. There are two predefined FloatingToolbarColors at FloatingToolbarDefaults.standardFloatingToolbarColors and FloatingToolbarDefaults.vibrantFloatingToolbarColors which you can use or modify. See also floatingActionButton for more information on the right FAB to use for proper styling.
contentPaddingthe padding applied to the content of this floating toolbar.
scrollBehaviora FloatingToolbarScrollBehavior. If provided, this FloatingToolbar will automatically react to scrolling. If your toolbar is positioned along a center edge of the screen (like left or right center), it's best to use this scroll behavior to make the entire toolbar scroll off-screen as the user scrolls. This would prevent the FAB from appearing off-center, which may occur in this case when using the expanded flag to simply expand or collapse the toolbar. Note that the toolbar will not react to scrolling in case a touch exploration service (e.g., TalkBack) is active.
shapethe shape used for this floating toolbar content.
floatingActionButtonPositionthe position of the floating toolbar's floating action button. By default, the FAB is placed at the bottom of the toolbar (i.e. aligned to the bottom).
animationSpecthe animation spec to use for this floating toolbar expand and collapse animation.
expandedShadowElevationthe elevation for the shadow below this floating toolbar when expanded.
collapsedShadowElevationthe elevation for the shadow below this floating toolbar when collapsed.
contentthe main content of this floating toolbar. The default layout here is a Column, so content inside will be placed vertically.

Code Examples

ExpandableVerticalFloatingToolbarSample

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun ExpandableVerticalFloatingToolbarSample() {
    var expanded by rememberSaveable { mutableStateOf(true) }
    Scaffold(
        content = { innerPadding ->
            Box(Modifier.padding(innerPadding)) {
                LazyColumn(
                    // Apply a floatingToolbarVerticalNestedScroll Modifier toggle the expanded
                    // state of the HorizontalFloatingToolbar.
                    modifier =
                        Modifier.floatingToolbarVerticalNestedScroll(
                            expanded = expanded,
                            onExpand = { expanded = true },
                            onCollapse = { expanded = false },
                        ),
                    state = rememberLazyListState(),
                    contentPadding = innerPadding,
                    verticalArrangement = Arrangement.spacedBy(8.dp),
                ) {
                    val list = (0..75).map { it.toString() }
                    items(count = list.size) {
                        Text(
                            text = list[it],
                            style = MaterialTheme.typography.bodyLarge,
                            modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
                        )
                    }
                }
                VerticalFloatingToolbar(
                    modifier = Modifier.align(Alignment.CenterEnd).offset(x = -ScreenOffset),
                    expanded = expanded,
                    leadingContent = { LeadingContent() },
                    trailingContent = { TrailingContent() },
                    content = {
                        FilledIconButton(
                            modifier = Modifier.height(64.dp),
                            onClick = { /* doSomething() */ },
                        ) {
                            Icon(Icons.Filled.Add, contentDescription = "Localized description")
                        }
                    },
                )
            }
        }
    )
}

OverflowingVerticalFloatingToolbarSample

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun OverflowingVerticalFloatingToolbarSample() {
    Scaffold(
        content = { innerPadding ->
            Box(Modifier.padding(innerPadding)) {
                LazyColumn(
                    state = rememberLazyListState(),
                    contentPadding = innerPadding,
                    verticalArrangement = Arrangement.spacedBy(8.dp),
                ) {
                    val list = (0..75).map { it.toString() }
                    items(count = list.size) {
                        Text(
                            text = list[it],
                            style = MaterialTheme.typography.bodyLarge,
                            modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
                        )
                    }
                }
                VerticalFloatingToolbar(
                    modifier = Modifier.align(Alignment.CenterEnd).offset(x = -ScreenOffset),
                    expanded = true,
                    leadingContent = { LeadingContent() },
                    trailingContent = {
                        AppBarColumn(
                            overflowIndicator = { menuState ->
                                IconButton(
                                    onClick = {
                                        if (menuState.isExpanded) {
                                            menuState.dismiss()
                                        } else {
                                            menuState.show()
                                        }
                                    }
                                ) {
                                    Icon(
                                        imageVector = Icons.Filled.MoreVert,
                                        contentDescription = "Localized description",
                                    )
                                }
                            }
                        ) {
                            clickableItem(
                                onClick = { /* doSomething() */ },
                                icon = {
                                    Icon(
                                        Icons.Filled.Download,
                                        contentDescription = "Localized description",
                                    )
                                },
                                label = "Download",
                            )
                            clickableItem(
                                onClick = { /* doSomething() */ },
                                icon = {
                                    Icon(
                                        Icons.Filled.Favorite,
                                        contentDescription = "Localized description",
                                    )
                                },
                                label = "Favorite",
                            )
                            clickableItem(
                                onClick = { /* doSomething() */ },
                                icon = {
                                    Icon(
                                        Icons.Filled.Add,
                                        contentDescription = "Localized description",
                                    )
                                },
                                label = "Add",
                            )
                            clickableItem(
                                onClick = { /* doSomething() */ },
                                icon = {
                                    Icon(
                                        Icons.Filled.Person,
                                        contentDescription = "Localized description",
                                    )
                                },
                                label = "Person",
                            )
                            clickableItem(
                                onClick = { /* doSomething() */ },
                                icon = {
                                    Icon(
                                        Icons.Filled.ArrowUpward,
                                        contentDescription = "Localized description",
                                    )
                                },
                                label = "ArrowUpward",
                            )
                        }
                    },
                    content = {
                        FilledIconButton(
                            modifier = Modifier.height(64.dp),
                            onClick = { /* doSomething() */ },
                        ) {
                            Icon(Icons.Filled.Add, contentDescription = "Localized description")
                        }
                    },
                )
            }
        }
    )
}

ScrollableVerticalFloatingToolbarSample

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun ScrollableVerticalFloatingToolbarSample() {
    val exitAlwaysScrollBehavior =
        FloatingToolbarDefaults.exitAlwaysScrollBehavior(exitDirection = End)
    Scaffold(
        modifier = Modifier.nestedScroll(exitAlwaysScrollBehavior),
        content = { innerPadding ->
            Box(Modifier.padding(innerPadding)) {
                LazyColumn(
                    state = rememberLazyListState(),
                    contentPadding = innerPadding,
                    verticalArrangement = Arrangement.spacedBy(8.dp),
                ) {
                    val list = (0..75).map { it.toString() }
                    items(count = list.size) {
                        Text(
                            text = list[it],
                            style = MaterialTheme.typography.bodyLarge,
                            modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
                        )
                    }
                }
                VerticalFloatingToolbar(
                    modifier = Modifier.align(Alignment.CenterEnd).offset(x = -ScreenOffset),
                    expanded = true,
                    leadingContent = { LeadingContent() },
                    trailingContent = { TrailingContent() },
                    content = {
                        FilledIconButton(
                            modifier = Modifier.height(64.dp),
                            onClick = { /* doSomething() */ },
                        ) {
                            Icon(Icons.Filled.Add, contentDescription = "Localized description")
                        }
                    },
                    scrollBehavior = exitAlwaysScrollBehavior,
                )
            }
        },
    )
}

VerticalFloatingToolbarWithFabSample

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun VerticalFloatingToolbarWithFabSample() {
    var expanded by rememberSaveable { mutableStateOf(true) }
    val vibrantColors = FloatingToolbarDefaults.vibrantFloatingToolbarColors()
    Scaffold { innerPadding ->
        Box(Modifier.padding(innerPadding)) {
            Column(
                Modifier.fillMaxWidth()
                    .padding(horizontal = 16.dp)
                    // Apply a floatingToolbarVerticalNestedScroll Modifier to the Column to toggle
                    // the expanded state of the VerticalFloatingToolbar.
                    .then(
                        Modifier.floatingToolbarVerticalNestedScroll(
                            expanded = expanded,
                            onExpand = { expanded = true },
                            onCollapse = { expanded = false },
                        )
                    )
                    .verticalScroll(rememberScrollState())
            ) {
                Text(text = remember { LoremIpsum().values.first() })
            }
            VerticalFloatingToolbar(
                expanded = expanded,
                floatingActionButton = {
                    // Match the FAB to the vibrantColors. See also StandardFloatingActionButton.
                    FloatingToolbarDefaults.VibrantFloatingActionButton(
                        onClick = { /* doSomething() */ }
                    ) {
                        Icon(Icons.Filled.Add, "Localized description")
                    }
                },
                modifier =
                    Modifier.align(Alignment.BottomEnd)
                        .offset(x = -ScreenOffset, y = -ScreenOffset),
                colors = vibrantColors,
                content = {
                    IconButton(onClick = { /* doSomething() */ }) {
                        Icon(Icons.Filled.Person, contentDescription = "Localized description")
                    }
                    IconButton(onClick = { /* doSomething() */ }) {
                        Icon(Icons.Filled.Edit, contentDescription = "Localized description")
                    }
                    IconButton(onClick = { /* doSomething() */ }) {
                        Icon(Icons.Filled.Favorite, contentDescription = "Localized description")
                    }
                    IconButton(onClick = { /* doSomething() */ }) {
                        Icon(Icons.Filled.MoreVert, contentDescription = "Localized description")
                    }
                },
            )
        }
    }
}

CenteredVerticalFloatingToolbarWithFabSample

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun CenteredVerticalFloatingToolbarWithFabSample() {
    val exitAlwaysScrollBehavior =
        FloatingToolbarDefaults.exitAlwaysScrollBehavior(exitDirection = End)
    val vibrantColors = FloatingToolbarDefaults.vibrantFloatingToolbarColors()
    Scaffold(modifier = Modifier.nestedScroll(exitAlwaysScrollBehavior)) { innerPadding ->
        Box(Modifier.padding(innerPadding)) {
            Column(
                Modifier.fillMaxWidth()
                    .padding(horizontal = 16.dp)
                    .verticalScroll(rememberScrollState())
            ) {
                Text(text = remember { LoremIpsum().values.first() })
            }
            VerticalFloatingToolbar(
                // Always expanded as the toolbar is right-centered. We will use a
                // FloatingToolbarScrollBehavior to hide both the toolbar and its FAB on scroll.
                expanded = true,
                floatingActionButton = {
                    // Match the FAB to the vibrantColors. See also StandardFloatingActionButton.
                    FloatingToolbarDefaults.VibrantFloatingActionButton(
                        onClick = { /* doSomething() */ }
                    ) {
                        Icon(Icons.Filled.Add, "Localized description")
                    }
                },
                modifier = Modifier.align(Alignment.CenterEnd).offset(x = -ScreenOffset),
                colors = vibrantColors,
                scrollBehavior = exitAlwaysScrollBehavior,
                content = {
                    IconButton(onClick = { /* doSomething() */ }) {
                        Icon(Icons.Filled.Person, contentDescription = "Localized description")
                    }
                    IconButton(onClick = { /* doSomething() */ }) {
                        Icon(Icons.Filled.Edit, contentDescription = "Localized description")
                    }
                    IconButton(onClick = { /* doSomething() */ }) {
                        Icon(Icons.Filled.Favorite, contentDescription = "Localized description")
                    }
                    IconButton(onClick = { /* doSomething() */ }) {
                        Icon(Icons.Filled.MoreVert, contentDescription = "Localized description")
                    }
                },
            )
        }
    }
}