WideNavigationRail
Common
Component in Material 3 Compose
Material design wide navigation rail.
Wide navigation rails provide access to primary destinations in apps when using tablet and desktop screens.

Last updated:
Installation
dependencies {
implementation("androidx.compose.material3:material3:1.4.0-alpha12")
}
Overloads
@ExperimentalMaterial3ExpressiveApi
@Composable
fun WideNavigationRail(
modifier: Modifier = Modifier,
state: WideNavigationRailState = rememberWideNavigationRailState(),
shape: Shape = WideNavigationRailDefaults.containerShape,
colors: WideNavigationRailColors = WideNavigationRailDefaults.colors(),
header: @Composable (() -> Unit)? = null,
windowInsets: WindowInsets = WideNavigationRailDefaults.windowInsets,
arrangement: Arrangement.Vertical = WideNavigationRailDefaults.arrangement,
content: @Composable () -> Unit
)
Parameters
name | description |
---|---|
modifier | the [Modifier] to be applied to this wide navigation rail |
state | the [WideNavigationRailState] of this wide navigation rail |
shape | defines the shape of this wide navigation rail's container. |
colors | [WideNavigationRailColors] that will be used to resolve the colors used for this wide navigation rail. See [WideNavigationRailDefaults.colors] |
header | optional header that may hold a [FloatingActionButton] or a logo |
windowInsets | a window insets of the wide navigation rail |
arrangement | the [Arrangement.Vertical] of this wide navigation rail for its content. Note that if there's a header present, the items will be arranged on the remaining space below it, except for the center arrangement which considers the entire height of the container |
content | the content of this wide navigation rail, typically [WideNavigationRailItem]s |
Code Examples
WideNavigationRailCollapsedSample
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun WideNavigationRailCollapsedSample() {
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)
WideNavigationRail {
items.forEachIndexed { index, item ->
WideNavigationRailItem(
icon = {
Icon(
if (selectedItem == index) selectedIcons[index] else unselectedIcons[index],
contentDescription = null
)
},
label = { Text(item) },
selected = selectedItem == index,
onClick = { selectedItem = index }
)
}
}
}
WideNavigationRailExpandedSample
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun WideNavigationRailExpandedSample() {
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)
WideNavigationRail(
state = rememberWideNavigationRailState(initialValue = WideNavigationRailValue.Expanded)
) {
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 }
)
}
}
}
WideNavigationRailResponsiveSample
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun WideNavigationRailResponsiveSample() {
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)
val state = rememberWideNavigationRailState()
val scope = rememberCoroutineScope()
Row(Modifier.fillMaxWidth()) {
WideNavigationRail(
state = state,
header = {
IconButton(
modifier =
Modifier.padding(start = 24.dp).semantics {
// The button must announce the expanded or collapsed state of the rail
// for accessibility.
stateDescription =
if (state.currentValue == WideNavigationRailValue.Expanded) {
"Expanded"
} else {
"Collapsed"
}
},
onClick = {
scope.launch {
if (state.targetValue == WideNavigationRailValue.Expanded)
state.collapse()
else state.expand()
}
}
) {
if (state.targetValue == WideNavigationRailValue.Expanded) {
Icon(Icons.AutoMirrored.Filled.MenuOpen, "Collapse rail")
} else {
Icon(Icons.Filled.Menu, "Expand rail")
}
}
}
) {
items.forEachIndexed { index, item ->
WideNavigationRailItem(
railExpanded = state.targetValue == WideNavigationRailValue.Expanded,
icon = {
val imageVector =
if (selectedItem == index) {
selectedIcons[index]
} else {
unselectedIcons[index]
}
Icon(imageVector = imageVector, contentDescription = null)
},
label = { Text(item) },
selected = selectedItem == index,
onClick = { selectedItem = index }
)
}
}
val textString =
if (state.currentValue == WideNavigationRailValue.Expanded) {
"Expanded"
} else {
"Collapsed"
}
Column {
Text(modifier = Modifier.padding(16.dp), text = "Is animating: " + state.isAnimating)
Text(modifier = Modifier.padding(16.dp), text = "The rail is $textString.")
Text(
modifier = Modifier.padding(16.dp),
text =
"Note: The orientation of this demo has been locked to portrait mode, because" +
" landscape mode may result in a compact height in certain devices. For" +
" any compact screen dimensions, use a Navigation Bar instead."
)
}
}
// Lock the orientation for this demo as the navigation rail may look cut off in landscape in
// smaller screens.
val context = LocalContext.current
DisposableEffect(context) {
(context as? Activity)?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
onDispose {
(context as? Activity)?.requestedOrientation =
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
}
}
}