We just launched Compose Examples featuring over 150+ components! Check it out →

DismissibleModalWideNavigationRail

Common

Component in Material 3 Compose

A dismissible modal wide navigation rail.

Wide navigation rails provide access to primary destinations in apps when using tablet and desktop screens.

The dismissible modal wide navigation rail blocks interaction with the rest of an app’s content with a scrim when expanded. It is elevated above most of the app’s UI and doesn't affect the screen’s layout grid. When collapsed, the rail is hidden.

Last updated:

Installation

dependencies {
   implementation("androidx.compose.material3:material3:1.4.0-alpha01")
}

Overloads

@ExperimentalMaterial3ExpressiveApi
@Composable
fun DismissibleModalWideNavigationRail(
    onDismissRequest: () -> Unit,
    modifier: Modifier = Modifier,
    railState: DismissibleModalWideNavigationRailState =
        rememberDismissibleModalWideNavigationRailState(),
    shape: Shape = WideNavigationRailDefaults.modalContainerShape,
    colors: WideNavigationRailColors = WideNavigationRailDefaults.colors(),
    header: @Composable (() -> Unit)? = null,
    windowInsets: WindowInsets = WideNavigationRailDefaults.windowInsets,
    arrangement: WideNavigationRailArrangement = WideNavigationRailDefaults.Arrangement,
    gesturesEnabled: Boolean = true,
    properties: ModalWideNavigationRailProperties =
        DismissibleModalWideNavigationRailDefaults.Properties,
    content: @Composable () -> Unit
)

Parameters

namedescription
onDismissRequestexecutes when the user closes the rail, after it animates to [DismissibleModalWideNavigationRailValue.Closed]
modifierthe [Modifier] to be applied to this dismissible modal wide navigation rail
railStatestate of the dismissible modal wide navigation rail
shapedefines the shape of this dismissible modal wide navigation rail's container
colors[WideNavigationRailColors] that will be used to resolve the colors used for this dismissible modal wide navigation rail. See [WideNavigationRailDefaults.colors]
headeroptional header that may hold a [FloatingActionButton] or a logo
windowInsetsa window insets of this dismissible modal wide navigation rail
arrangementthe [WideNavigationRailArrangement] of this dismissible modal wide navigation rail
gesturesEnabledwhether the dismissible modal wide navigation rail can be interacted by gestures
properties[ModalWideNavigationRailProperties] for further customization of this modal expanded navigation rail's window behavior
contentthe content of this dismissible modal wide navigation rail, typically [WideNavigationRailItem]s with [NavigationItemIconPosition.Start] icon position

Code Example

DismissibleModalWideNavigationRailSample

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun DismissibleModalWideNavigationRailSample() {
    var selectedItem by remember { mutableIntStateOf(0) }
    val items = listOf("Home", "Search", "Settings")
    val selectedIcons = listOf(Icons.Filled.Home, Icons.Filled.Favorite, Icons.Filled.Star)
    val unselectedIcons =
        listOf(Icons.Outlined.Home, Icons.Outlined.FavoriteBorder, Icons.Outlined.StarBorder)
    var openModalRail by rememberSaveable { mutableStateOf(false) }
    var dismissRailOnItemSelection by rememberSaveable { mutableStateOf(true) }
    val modalRailState = rememberDismissibleModalWideNavigationRailState()
    val scope = rememberCoroutineScope()

    Row(Modifier.fillMaxSize()) {
        if (openModalRail) {
            DismissibleModalWideNavigationRail(
                onDismissRequest = { openModalRail = false },
                railState = modalRailState
            ) {
                items.forEachIndexed { index, item ->
                    WideNavigationRailItem(
                        railExpanded = true,
                        icon = {
                            Icon(
                                if (selectedItem == index) selectedIcons[index]
                                else unselectedIcons[index],
                                contentDescription = null
                            )
                        },
                        label = { Text(item) },
                        selected = selectedItem == index,
                        onClick = {
                            selectedItem = index
                            if (dismissRailOnItemSelection) {
                                // Note: If you provide logic outside of onDismissRequest to close
                                // the rail, you must additionally handle intended state cleanup, if
                                // any.
                                scope
                                    .launch {
                                        // Add a minimum delay so that the selected state of the
                                        // item is properly announced to screen readers before the
                                        // rail closes.
                                        delay(250)
                                        modalRailState.close()
                                    }
                                    .invokeOnCompletion { openModalRail = false }
                            }
                        }
                    )
                }
            }
        }

        Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
            Button(onClick = { openModalRail = !openModalRail }, Modifier.padding(32.dp)) {
                Text(text = "Open modal rail")
            }
            Row(
                Modifier.toggleable(
                    value = dismissRailOnItemSelection,
                    role = Role.Checkbox,
                    onValueChange = { checked -> dismissRailOnItemSelection = checked }
                )
            ) {
                Checkbox(checked = dismissRailOnItemSelection, onCheckedChange = null)
                Spacer(Modifier.width(16.dp))
                Text("Dismiss rail on item selection.")
            }
        }
    }
}
by @alexstyl