Appearance
Navigation Rail
Navigation rail provides access to primary destinations in your app on tablet and desktop screens.

Contents
Design and API Documentation
Using navigation rail
Before you can use the Material Navigation Rail, you need to add a dependency to the Material Components for Android library. For more information, go to the Getting started page.
A typical layout will look similar to this:
xml
<com.google.android.material.navigationrail.NavigationRailView
android:id="@+id/navigation_rail"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:menu="@menu/navigation_rail_menu" />Note: The width of a NavigationRailView will be 80dp wide by default.The width of the rail can be changed by setting the android:layout_widthattribute to a specific DP value.
In navigation_rail_menu.xml inside a menu resource directory:
xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/alarms"
android:enabled="true"
android:icon="@drawable/icon_alarms"
android:title="@string/alarms_destination_label"/>
<item
android:id="@+id/schedule"
android:enabled="true"
android:icon="@drawable/icon_clock"
android:title="@string/schedule_destination_label"/>
<item
android:id="@+id/timer"
android:enabled="true"
android:icon="@drawable/icon_sand_clock"
android:title="@string/timer_destination_label"/>
<item
android:id="@+id/stopwatch"
android:enabled="true"
android:icon="@drawable/icon_stop_watch"
android:title="@string/stopwatch_destination_label"/>
</menu>Note: NavigationRailView displays three to no more than seven app destinations, and can include a header view. Each destination is represented by an icon and a text label.
In code:
kt
// Listeners are defined on the super class NavigationBarView
// to support both NavigationRail and BottomNavigation with the
// same listeners
NavigationBarView.OnNavigationItemSelectedListener { item ->
when(item.itemId) {
R.id.alarms -> {
// Respond to alarm navigation item click
true
}
R.id.schedule -> {
// Respond to schedule navigation item click
true
}
else -> false
}
}There's also a method for detecting if navigation items have been reselected:
kt
navigationRail.setOnNavigationItemReselectedListener { item ->
when(item.itemId) {
R.id.item1 -> {
// Respond to navigation item 1 reselection
}
R.id.item2 -> {
// Respond to navigation item 2 reselection
}
}
}Which results in:

By default, Navigation rail adds top and bottom padding according to top and bottom window insets—helping the header layout and menu items dodge system spaces. This is controlled by the android:fitsSystemWindowInsets attribute, which is set to true by default. To remove this behavior, set android:fitsSystemWindowInsets to false or opt in or out of the top and bottom insets independently by using app:paddingTopSystemWindowInsets and app:paddingBottomSystemWindowInsets.
API and source code:
NavigationRailView
Making navigation rail accessible
You should set an android:title for each of your menu items so that screen readers like TalkBack can properly announce what each navigation item represents:
xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
...
android:title="@string/text_label"/>
...
</menu>The labelVisibilityMode attribute can be used to adjust the behavior of the text labels for each navigation item. There are four visibility modes:
LABEL_VISIBILITY_AUTO(default): The label behaves as “labeled” when there are 3 items or less, or “selected” when there are 4 items or moreLABEL_VISIBILITY_SELECTED: The label is only shown on the selected navigation itemLABEL_VISIBILITY_LABELED: The label is shown on all navigation itemsLABEL_VISIBILITY_UNLABELED: The label is hidden for all navigation items
Adding a header view
The rail provides a convenient container for anchoring a header view, such as a FloatingActionButton or a logo, to the top of the rail, using the app:headerLayout attribute.

xml
<com.google.android.material.navigationrail.NavigationRailView
android:id="@+id/navigation_rail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:headerLayout="@layout/navigation_rail_fab"
app:menu="@menu/navigation_rail_menu" />The header view can also be added or removed at runtime using the following methods:
| Method | Description |
|---|---|
void addHeaderView(@NonNull View view) | The specified header view will be attached to the NavigationRailView, so that it will appear at the top. If the view already has a header view attached to it, it will be removed first. |
void removeHeaderView() | Detaches the current header view if any, from the Navigation Rail. |
The following methods can be used to manipulate the header view at runtime.
| Method | Description |
|---|---|
@Nullable view getHeaderView() | Returns an instance of the header view associated with the Navigation Rail, null if none was currently attached. |
Adding badges
Rail icons can include badges on the upper right corner of the icon. Badges convey dynamic information about the associated destination, such as counts or status.

Initialize and show a BadgeDrawable associated with menuItemId. Subsequent calls to this method will reuse the existing BadgeDrawable:
kt
var badge = navigationRail.getOrCreateBadge(menuItemId)
badge.isVisible = true
// An icon only badge will be displayed unless a number or text is set:
badge.number = 99 // or badge.text = "New"As best practice, if you need to temporarily hide the badge, for example until the next notification is received, change the visibility of BadgeDrawable:
kt
val badgeDrawable = navigationRail.getBadge(menuItemId)
if (badgeDrawable != null) {
badgeDrawable.isVisible = false
badgeDrawable.clearNumber() // or badgeDrawable.clearText()
}To remove any BadgeDrawables that are no longer needed:
kt
navigationRail.removeBadge(menuItemId)See the BadgeDrawable documentation for more information.
Navigation rail example
The following example shows a navigation rail with four icons:
- Alarms
- Schedule
- Timers
- Stopwatch
In navigation_rail_menu.xml inside a menu resource directory:
xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/alarms"
android:enabled="true"
android:icon="@drawable/icon_alarm"
android:title="@string/alarms_destination_label"/>
<item
android:id="@+id/schedule"
android:enabled="true"
android:icon="@drawable/icon_clock"
android:title="@string/schedule_destination_label"/>
<item
android:id="@+id/timers"
android:enabled="true"
android:icon="@drawable/icon_sand_clock"
android:title="@string/timers_destination_label"/>
<item
android:id="@+id/stopwatch"
android:enabled="true"
android:icon="@drawable/icon_stop_watch"
android:title="@string/stopwatch_destination_label"/>
</menu>In code:
kt
navigationRail.selectedItemId = R.id.imagesAnatomy and key properties
The following is an anatomy diagram for the navigation rail:

- Container
- Header - menu icon (optional)
- Header - Floating action button (optional)
- Icon - active
- Active indicator
- Label text - active (optional)
- Icon - inactive
- Label text - inactive (optional)
- Large badge (optional)
- Large badge label (optional)
- Badge (optional)
Container attributes
| Element | Attribute | Related methods | Default value |
|---|---|---|---|
| Color | app:backgroundTint | N/A | ?attr/colorSurface |
| Elevation | app:elevation | setElevation | 0dp |
| Fits system windows | android:fitsSystemWindows | getFitsSystemWindowssetFitsSystemWindows | true |
| Padding top system window insets | app:paddingTopSystemWindowInsets | N/A | null |
| Padding bottom system window insets | app:paddingBottomSystemWindowInsets | N/A | null |
Header attributes
| Element | Attribute | Related methods | Default value |
|---|---|---|---|
| Header view | app:headerLayout | addHeaderViewremoveHeaderViewgetHeaderView | N/A |
| Header bottom margin | app:headerMarginBottom | N/A | 8dp |
See the FAB documentation for more attributes.
Navigation Menu attributes
| Element | Attribute | Related methods | Default value |
|---|---|---|---|
| Menu gravity | app:menuGravity | setMenuGravitygetMenuGravity | TOP|CENTER_HORIZONTAL |
| Top margin | app:contentMarginTop | N/A | N/A |
Navigation item attributes
| Element | Attribute | Related methods | Default value |
|---|---|---|---|
| Menu resource | app:menu | inflateMenugetMenu | N/A |
| Ripple (inactive) | app:itemRippleColor | setItemRippleColorgetItemRippleColor | ?attr/colorPrimary at 12% (see all states) |
| Ripple (active) | app:itemRippleColor | setItemRippleColorgetItemRippleColor | ?attr/colorPrimary at 12% (see all states) |
| Label visibility mode | app:labelVisibilityMode | setLabelVisibilityModegetLabelVisibilityMode | LABEL_VISIBILITY_AUTO |
| Item minimum height | app:itemMinHeight | setItemMinimumHeightgetItemMinimumHeight | NO_ITEM_MINIMUM_HEIGHT |
| Item spacing | app:itemSpacing | setItemSpacinggetItemSpacing | 0dp |
| Item Gravity | app:itemGravity | setItemGravitygetItemGravity | TOP_CENTER |
Note: If there's not enough room, itemMinHeight and itemSpacing may not be respected in order to fit the items.
Active indicator attributes
| Element | Attribute | Related methods | Default value |
|---|---|---|---|
| Color | android:color | setItemActiveIndicatorColorgetItemActiveIndicatorColor | ?attr/colorSecondaryContainer |
| Width | android:width | setItemActiveIndicatorWidthgetItemActiveIndicatorWidth | 56dp |
| Height | android:height | setItemActiveIndicatorHeightgetItemActiveIndicatorHeight | 32dp |
| Shape | app:shapeAppearance | setItemActiveIndicatorShapeAppearancegetItemActiveIndicatorShapeAppearance | 50% rounded |
| Margin horizontal | app:marginHorizontal | setItemActiveIndicatorMarginHorizontalgetItemActiveIndicatorMarginHorizontal | 4dp |
| Padding between indicator and label | app:activeIndicatorLabelPadding | setActiveIndicatorLabelPadding getActiveIndicatorLabelPadding | 4dp |
| Expanded Width | expandedWidth | setItemExpandedActiveIndicatorWidthgetItemExpandedActiveIndicatorWidth | HUG |
| Expanded Height | expandedHeight | setItemExpandedActiveIndicatorHeightgetItemExpandedActiveIndicatorHeight | 56dp |
| Expanded Margin horizontal | app:expandedMarginHorizontal | setItemExpandedActiveIndicatorMarginHorizontalgetItemExpandedActiveIndicatorMarginHorizontal | 20dp |
Note: The expanded active indicator refers to the active indicator that expands to wrap the content of the Navigation Rail item when the itemIconGravity value is equal to START.
Icon attributes
| Element | Attribute | Related methods | Default value |
|---|---|---|---|
| Icon | android:icon in the menu resource | N/A | N/A |
| Size | app:itemIconSize | setItemIconSizesetItemIconSizeResgetItemIconSize | 24dp |
| Color (inactive) | app:itemIconTint | setItemIconTintListgetItemIconTintList | ?attr/colorOnSurfaceVariant |
| Color (active) | app:itemIconTint | setItemIconTintListgetItemIconTintList | ?attr/colorOnSecondaryContainer |
| Gravity | app:itemIconGravity | setItemIconGravitygetItemIconGravity | TOP |
Text label attributes
| Element | Attribute | Related methods | Default value |
|---|---|---|---|
| Text label | android:title in the menu resource | N/A | N/A |
| Color (inactive) | app:itemTextColor | setItemTextColorgetItemTextColor | ?attr/colorOnSurfaceVariant |
| Color (active) | app:itemTextColor | setItemTextColorgetItemTextColor | ?attr/colorOnSurface |
| Typography (inactive) | app:itemTextAppearanceInactiveapp:horizontalItemTextAppearanceInactive | setItemTextAppearanceInactivegetItemTextAppearanceInactivesetHorizontalItemTextAppearanceInactivegetHorizontalItemTextAppearanceInactive | ?attr/textAppearanceTitleSmall for regular item configuration, ?attr/textAppearanceLabelLarge for horizontal |
| Typography (active) | app:itemTextAppearanceActiveapp:horizontalItemTextAppearanceActive | setItemTextAppearanceActivegetItemTextAppearanceActivesetHorizontalItemTextAppearanceActivegetHorizontalItemTextAppearanceActive | ?attr/textAppearanceTitleSmall for regular item configuration, ?attr/textAppearanceLabelLarge for horizontal |
| Typography (active) | app:itemTextAppearanceActiveBoldEnabled | setItemTextAppearanceActiveBoldEnabled | true |
Styles
| Element | Style | Container color | Icon/Text label color (inactive) | Icon/Text label color (active) |
|---|---|---|---|---|
| Default style | Widget.Material3.NavigationRailView | ?attr/colorSurface | ?attr/colorOnSurfaceVariant | ?attr/colorOnSurface?attr/colorOnSecondaryContainer |
Default style theme attribute: ?attr/navigationRailStyle
See the full list of styles, navigation bar attributes, and navigation rail attributes.
Theming a navigation rail
Navigation rail supports Material Theming, which can customize color and typography.
Navigation rail theming example
API and source code:
NavigationRailView
The following example shows a navigation rail with Material Theming.

Implementing navigation rail theming
Use theme attributes and a style in res/values/styles.xml which apply to all navigation rails and affect other components:
xml
<style name="Theme.App" parent="Theme.Material3.*">
...
<item name="colorPrimary">@color/shrine_theme_light_primary</item>
<item name="colorSecondaryContainer">@color/shrine_theme_light_secondaryContainer</item>
<item name="colorOnSecondaryContainer">@color/shrine_theme_light_onSecondaryContainer</item>
<item name="colorTertiaryContainer">@color/shrine_theme_light_tertiaryContainer</item>
<item name="colorOnTertiaryContainer">@color/shrine_theme_light_onTertiaryContainer</item>
<item name="colorError">@color/shrine_theme_light_error</item>
<item name="colorErrorContainer">@color/shrine_theme_light_errorContainer</item>
<item name="colorOnError">@color/shrine_theme_light_onError</item>
<item name="colorOnErrorContainer">@color/shrine_theme_light_onErrorContainer</item>
<item name="colorSurface">@color/shrine_theme_light_surface</item>
<item name="colorOnSurface">@color/shrine_theme_light_onSurface</item>
<item name="colorOnSurfaceVariant">@color/shrine_theme_light_onSurfaceVariant</item>
</style>Use a default style theme attribute, styles, and a theme overlay, which apply to all navigation rails but do not affect other components:
xml
<style name="Theme.App" parent="Theme.Material3.*">
...
<item name="navigationRailStyle">@style/Widget.App.NavigationRailView</item>
</style>
<style name="Widget.App.NavigationRailView" parent="Widget.Material3.NavigationRailView">
<item name="materialThemeOverlay">@style/ThemeOverlay.App.NavigationRailView</item>
</style>
<style name="ThemeOverlay.App.NavigationRailView" parent="">
<item name="colorPrimary">@color/shrine_theme_light_primary</item>
<item name="colorSecondaryContainer">@color/shrine_theme_light_secondaryContainer</item>
<item name="colorOnSecondaryContainer">@color/shrine_theme_light_onSecondaryContainer</item>
<item name="colorTertiaryContainer">@color/shrine_theme_light_tertiaryContainer</item>
<item name="colorOnTertiaryContainer">@color/shrine_theme_light_onTertiaryContainer</item>
<item name="colorError">@color/shrine_theme_light_error</item>
<item name="colorErrorContainer">@color/shrine_theme_light_errorContainer</item>
<item name="colorOnError">@color/shrine_theme_light_onError</item>
<item name="colorOnErrorContainer">@color/shrine_theme_light_onErrorContainer</item>
<item name="colorSurface">@color/shrine_theme_light_surface</item>
<item name="colorOnSurface">@color/shrine_theme_light_onSurface</item>
<item name="colorOnSurfaceVariant">@color/shrine_theme_light_onSurfaceVariant</item>
</style>Or use the style in the layout, which affects only this specific navigation rail bar:
xml
<com.google.android.material.navigationrail.NavigationRailView
...
style="@style/Widget.App.NavigationRailView"
/>