Back to Material Components Android

Navigation drawers

docs/components/NavigationDrawer.md

1.13.030.5 KB
Original Source
<!--docs: title: "Navigation drawer" layout: detail section: components excerpt: "Navigation drawers provide access to destinations in your app." iconId: navigation-drawer path: /catalog/navigation-drawer/ -->

Navigation drawers

Note: The navigation drawer is being deprecated in the Material 3 expressive update. For those who have updated, use an expanded navigation rail, which has mostly the same functionality of the navigation drawer and adapts better across window size classes.

Navigation drawers provide access to destinations in your app. There are two variants of navigation drawers.

  1. Standard navigation drawer
  2. Modal navigation drawer

Note: Images use various dynamic color schemes.

Design & API documentation

Anatomy

  1. Container
  2. Headline
  3. Label text
  4. Icon
  5. Active indicator
  6. Badge label text
  7. Scrim

More details on anatomy items are available in the component guidelines.

M3 Expressive update

The navigation drawer is being deprecated. Use the expanded navigation rail instead. More on M3 Expressive

Key properties

Container attributes

ElementAttribute(s)Related method(s)Default value
Colorandroid:backgroundsetBackground
getBackground?attr/colorSurfaceContainerLow
Shapeapp:shapeAppearance
app:shapeAppearanceOverlayN/Anull
Elevationapp:elevation (can be used on NavigationView or DrawerLayout)setElevation
getElevation0dp (NavigationView) or 1dp (DrawerLayout)
Max widthandroid:maxWidthN/A280dp
Fits system windowsandroid:fitsSystemWindowssetFitsSystemWindows
getFitsSystemWindowstrue
Drawer corner sizedrawerLayoutCornerSizeN/A16dp

Header attributes

ElementAttributeRelated method(s)Default value
Layoutapp:headerLayoutaddHeaderView
inflateHeaderView
getHeaderView
getHeaderCount
removeHeaderViewnull

Divider attributes

ElementAttributeRelated method(s)Default value
Dividerandroid:listDivider in app themeN/AVaries per platform version
HeightN/A (see layout)N/A1dp
Insetapp:dividerInsetStart
app:dividerInsetEndsetDividerInsetStart
getDividerInsetStart
setDividerInsetEnd
getDividerInsetEnd28dp
28dp

Item attributes

ElementAttribute(s)Related method(s)Default value
Colorapp:itemShapeFillColorN/A?attr/colorSecondaryContainer
Shapeapp:itemShapeAppearance
app:itemShapeAppearanceOverlayN/A@style/ShapeAppearance.Material3.Corner.Full
(?attr/shapeCornerFamily and corner size 50%)
Insetsapp:itemShapeInsetStart
app:itemShapeInsetTop
app:itemShapeInsetEnd
app:itemShapeInsetBottomN/A12dp
0dp
12dp
0dp
Horizontal paddingapp:itemHorizontalPaddingsetItemHorizontalPadding
setItemHorizontalPaddingResource
getItemHorizontalPadding28dp
Vertical paddingapp:itemVerticalPaddingsetItemVerticalPadding
setItemVerticalPaddingResource
getItemVerticalPadding4dp

Text attributes

ElementAttributeRelated method(s)Default value
Colorapp:itemTextColorsetItemTextColor
getItemTextColor?attr/colorOnSecondaryContainer when active else ?attr/colorOnSurfaceVariant
Typographyapp:itemTextAppearancesetItemTextAppearance?attr/textAppearanceLabelLarge
Typography (active)app:itemTextAppearanceActiveBoldEnabledsetItemTextAppearanceActiveBoldEnabledtrue
Max linesapp:itemMaxLinessetItemMaxLines
getItemMaxLines1

Icon attributes

ElementAttributeRelated method(s)Default value
Colorapp:itemIconTintsetIconItemTintList
getIconItemTintList?attr/colorOnSecondaryContainer when active else ?attr/colorOnSurfaceVariant
Sizeapp:itemIconSizesetItemIconSize24dp
Paddingapp:itemIconPaddingsetItemIconPadding
setItemIconPaddingResource
getItemIconPadding12dp

Subtitle attributes

ElementAttributeRelated method(s)Default value
Colorapp:subheaderColorN/A?attr/colorOnSurfaceVariant
Typographyapp:subheaderTextAppearanceN/A?attr/textAppearanceTitleSmall
Max linesN/AN/A1
HeightN/AN/A?attr/listPreferredItemHeightSmall
Paddingapp:subheaderInsetStart
app:subheaderInsetEndsetSubheaderInsetStart
getSubheaderInsetStart
setSubheaderInsetEnd
getSubheaderInsetEnd28dp and 28dp

Scrim attributes

ElementAttributeRelated method(s)Default value
ColorN/AsetScrimColor on DrawerLayoutBlack at 60% opacity
Window Insetsapp:topInsetScrimEnabled
app:bottomScrimEnabled
app:startScrimEnabled
app:endScrimEnabledsetTopInsetScrimEnabled
isTopInsetScrimEnabled
setBottomInsetScrimEnabled
isBottomInsetScrimEnabled
setStartInsetScrimEnabled
isStartInsetScrimEnabled
setEndInsetScrimEnabled
isEndInsetScrimEnabledtrue
ElementStyleTheme attribute
Default styleWidget.Material3.NavigationView?attr/navigationViewStyle

DrawerLayout styles

ElementStyleTheme attribute
Default styleWidget.Material3.DrawerLayout?attr/drawerLayoutStyle

Variants of navigation drawer

<details> <summary><h3>Standard navigation drawer</h3></summary>

Standard navigation drawers allow interaction with both screen content and the drawer at the same time. They can be used on tablet and desktop, but they aren’t suitable for mobile devices due to limited screen size.

API and source code:

Standard navigation drawer example

The following example shows a permanently visible standard navigation drawer.

In the layout:

xml
<androidx.constraintlayout.widget.ConstraintLayout
    ...
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.navigation.NavigationView
        ...
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        app:layout_constraintStart_toStartOf="parent" />

    <!-- Screen content (constrained to end of navigationView) -->

</androidx.constraintlayout.widget.ConstraintLayout>

In res/values/themes.xml:

xml
<style name="Theme.App" parent="Theme.Material3.DayNight.*">
    <item name="android:windowTranslucentStatus">true</item>
</style>

In res/layout/header_navigation_drawer.xml:

xml
<LinearLayout
    ...
    android:fitsSystemWindows="true">

    ...

</LinearLayout>
</details> <details> <summary><h3>Modal navigation drawer</h3></summary>

Modal navigation drawers block interaction with the rest of an app’s content with a scrim. They are elevated above most of the app’s UI and don’t affect the screen’s layout grid.

They are primarily used for mobile devices where screen space is limited, and can be replaced by standard drawers on tablet and desktop.

DrawerLayout is used in conjunction with NavigationDrawer to achieve the modal navigation drawer.

API and source code:

Modal navigation drawer example

The following example shows a modal navigation drawer.

In the layout:

xml
<androidx.drawerlayout.widget.DrawerLayout
    ...
    android:id="@+id/drawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:openDrawer="start">

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">

        <!-- Screen content -->
        <!-- Use app:layout_behavior="@string/appbar_scrolling_view_behavior" to fit below top app bar -->

    </androidx.coordinatorlayout.widget.CoordinatorLayout>

    <com.google.android.material.navigation.NavigationView
        ...
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start" />

</androidx.drawerlayout.widget.DrawerLayout>

In res/values/themes.xml:

xml
<style name="Theme.App" parent="Theme.Material3.DayNight.*">
    <item name="android:windowTranslucentStatus">true</item>
</style>

In res/layout/header_navigation_drawer.xml:

xml
<LinearLayout
    ...
    android:fitsSystemWindows="true">

    ...

</LinearLayout>

In code:

kt
topAppBar.setNavigationOnClickListener {
    drawerLayout.open()
}

navigationView.setNavigationItemSelectedListener { menuItem ->
    // Handle menu item selected
    menuItem.isChecked = true
    drawerLayout.close()
    true
}

For more information on top app bars see the documentation.

</details>

Code implementation

Before you can use navigation drawers, you need to add a dependency to the Material components for Android library. For more information, go to the Getting started page. For modal navigation drawers you also need to add a dependency to the AndroidX DrawerLayout library. For more information go to the releases page.

<details> <summary><h3>Adding navigation drawer</h3></summary>

The content of all navigation drawer types can be implemented using a NavigationView.

xml
<com.google.android.material.navigation.NavigationView
  android:id="@+id/navigationView"
  ... />

Note: The layout_width and layout_height attributes should be set to wrap_content, match_parent, or a custom dimension depending on the navigation drawer type and parent ViewGroup.

</details> <details> <summary><h3>Adding menu</h3></summary>

In the layout:

xml
<com.google.android.material.navigation.NavigationView
    ...
    app:menu="@menu/navigation_drawer" />

In res/menu/navigation_drawer.xml:

xml
<menu ...>

  <item
    android:id="@+id/main_item"
    android:title="@string/mail_subheader_title">
      <menu>
        <item
          android:id="@+id/inbox_item"
          android:icon="@drawable/ic_inbox_24px"
          android:title="@string/inbox_title"
          android:checkable="true"/>
        <item
          android:id="@+id/outbox_item"
          android:icon="@drawable/ic_outbox_24px"
          android:title="@string/outbox_title"
          android:checkable="true"/>
        <item
          android:id="@+id/favourites_item"
          android:icon="@drawable/ic_favourites_24px"
          android:title="@string/favourites_title"
          android:checkable="true">
      </menu>
  </item>

</menu>
</details> <details> <summary><h3>Adding header</h3></summary>

In the layout:

xml
<com.google.android.material.navigation.NavigationView
    ...
    app:headerLayout="@layout/header_navigation_drawer" />

In res/layout/header_navigation_drawer.xml:

xml
<LinearLayout
    ...
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:layout_marginStart="24dp"
        android:layout_marginEnd="24dp"
        android:textAppearance="?attr/textAppearanceHeadlineSmall"
        android:textColor="?attr/colorOnSurface"
        android:text="@string/header_title" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="24dp"
        android:layout_marginStart="24dp"
        android:layout_marginEnd="24dp"
        android:textAppearance="?attr/textAppearanceTitleSmall"
        android:textColor="?attr/colorOnSurfaceVariant"
        android:text="@string/header_text" />

</LinearLayout>
</details> <details> <summary><h3>Adding dividers and subtitles</h3></summary>

Dividers are automatically added between <item> groups with unique IDs or <group>s with unique IDs. When a sub-<menu> is added to an item it is treated as a subtitle.

In res/menu/navigation_drawer.xml:

xml
<menu ...>
  <item
    android:id="@+id/main_item"
    android:title="@string/mail_subheader_title">
      <menu>
        <item
          android:id="@+id/search_item"
          android:icon="@drawable/ic_search_24px"
          android:title="@string/search_title"
          android:checkable="true"
          app:showAsAction="ifRoom"/>
        <item
          android:id="@+id/rotation_item"
          android:icon="@drawable/ic_3d_rotation_24px"
          android:title="@string/3d_title"
          android:checkable="true"
          app:showAsAction="ifRoom"/>
        <item
          android:id="@+id/accelerator_item"
          android:icon="@drawable/ic_accelerator_24px"
          android:title="@string/accelerator_title"
          android:checkable="true"
          app:showAsAction="ifRoom"/>
        <item
          android:id="@+id/dashboard_item"
          android:icon="@drawable/ic_dashboard_24px"
          android:title="@string/dashboard_title"
          android:checkable="true"
          app:showAsAction="ifRoom"/>
      </menu>
  </item>
  <item
    android:id="@+id/labels_item"
    android:title="@string/labels_subheader_title">
      <menu>
        <item
          android:id="@+id/label_one"
          android:icon="@drawable/ic_label_24px"
          android:title="@string/label_one_title"
          android:checkable="true"
          app:showAsAction="ifRoom"/>
        <item
          android:id="@+id/label_two"
          android:icon="@drawable/ic_label_24px"
          android:title="@string/label_two_title"
          android:checkable="true"
          app:showAsAction="ifRoom"/>
      </menu>
  </item>

</menu>
</details> <details> <summary><h3>Making navigation drawers accessible</h3></summary>

Navigation drawers support content labeling for accessibility and are readable by most screen readers, such as TalkBack. Text rendered in menu items is automatically provided to accessibility services. Additional content labels are optional but recommended.

For more information on content labels, go to the Android accessibility help guide.

Important: Ensure that there is a way to close the navigation drawer through keyboard navigation by listening for the esc key in your activity and closing open drawers.

java
  @Override
  public boolean dispatchKeyEvent(KeyEvent keyEvent) {
    if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_ESCAPE && drawerLayout.isDrawerOpen(navigationView)) {
      drawerLayout.closeDrawer(navigationView);
      return true;
    }
    return super.dispatchKeyEvent(keyEvent);
  }
</details> <details> <summary><h3>Setting content descriptions</h3></summary>

A content description can be set on <item>s in the NavigationView menu so that screen readers like TalkBack are able to announce their purpose or action. This can be done in XML using the android:contentDescription attribute or programmatically with navigationView.menu.findItem(R.id.itemId)#setContentDescription (on API 26 and above).

Any ImageViews within the header layout should also have a content description set.

</details> <details> <summary><h3>Opening and closing navigation drawers</h3></summary>

To open navigation drawers, use clickable widgets that meet the minimum touch target size of 48dp and are properly labeled for accessibility. To close navigation drawers, consider doing the same but bear in mind that clicking on menu items or an optional scrim should also serve this purpose.

</details> <details> <summary><h3>Using navigation drawers with the navigation component</h3></summary>

Navigation drawers can be used with the AndroidX navigation library. For more information, go to the documentation.

</details> <details> <summary><h3>Predictive back</h3></summary>

The NavigationView component automatically supports predictive back when it is set up within a DrawerLayout, as mentioned in the sections above. No further integration is required on the app side other than the general predictive back prerequisites and migration steps mentioned here.

Visit the predictive back design guidelines to see how the component behaves when a user swipes back.

</details>

Customizing navigation drawers

Theming navigation drawers

Navigation drawers support the customization of color, typography, and shape.

Navigation drawer theming example

API and source code:

The following example shows a navigation drawer with Material theming.

Implementing navigation drawer theming

Use theme attributes, default style theme attributes, and styles in res/values/styles.xml, which applies to all navigation drawers and affects other components:

xml
<style name="Theme.App" parent="Theme.Material3.*">
    ...
    <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="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>
    <item name="colorOutline">@color/shrine_theme_light_outline</item>
    <item name="textAppearanceTitleSmall">@style/TextAppearance.App.TitleSmall</item>
    <item name="textAppearanceLabelLarge">@style/TextAppearance.App.LabelLarge</item>
</style>

<style name="TextAppearance.App.TitleSmall" parent="TextAppearance.Material3.TitleSmall">
    <item name="fontFamily">@font/rubik</item>
    <item name="android:fontFamily">@font/rubik</item>
</style>

<style name="TextAppearance.App.LabelLarge" parent="TextAppearance.Material3.LabelLarge">
    <item name="fontFamily">@font/rubik</item>
    <item name="android:fontFamily">@font/rubik</item>
</style>

<style name="Widget.App.NavigationView" parent="Widget.Material3.NavigationView">
    <item name="itemIconTint">@color/navigation_item_color</item>
    <item name="itemTextColor">@color/navigation_item_color</item>
    <item name="itemShapeFillColor">@color/navigation_item_background_color</item>
</style>

In res/color/navigation_item_color.xml:

xml
<selector ...>
    <item android:color="?attr/colorOnTertiaryContainer" android:state_checked="true"/>
    <item android:alpha="@dimen/material_emphasis_disabled" android:color="?attr/colorOnSurface" android:state_enabled="false"/>
    <item android:color="?attr/colorOnSurfaceVariant"/>
</selector>

In res/color/navigation_item_background_color.xml:

xml
<selector ...>
    <item android:alpha="@dimen/material_emphasis_disabled" android:color="?attr/colorTertiaryContainer" android:state_activated="true"/>
    <item android:alpha="@dimen/material_emphasis_disabled" android:color="?attr/colorTertiaryContainer" android:state_checked="true"/>
    <item android:color="@android:color/transparent"/>
</selector>

Use default style theme attributes, styles and theme overlays which apply to all navigation drawers but do not affect other components:

xml
<style name="Theme.App" parent="Theme.Material3.*">
    ...
    <item name="navigationViewStyle">@style/Widget.App.NavigationView</item>
</style>

<style name="Widget.App.NavigationView" parent="Widget.Material3.NavigationView">
    <item name="materialThemeOverlay">@style/ThemeOverlay.App.NavigationView</item>
    <item name="itemIconTint">@color/navigation_item_color</item>
    <item name="itemTextColor">@color/navigation_item_color</item>
    <item name="itemShapeFillColor">@color/navigation_item_background_color</item>
</style>

<style name="ThemeOverlay.App.NavigationView" parent="">
    <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="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>
    <item name="colorOutline">@color/shrine_theme_light_outline</item>
    <item name="textAppearanceTitleSmall">@style/TextAppearance.App.TitleSmall</item>
    <item name="textAppearanceLabelLarge">@style/TextAppearance.App.LabelLarge</item>
</style>

Use the style in the layout, which affects only this navigation drawer:

xml
<com.google.android.material.navigation.NavigationView
    ...
    style="@style/Widget.App.NavigationView" />