Material 3 Navigation Drawers
Overview
Navigation drawers provide access to app destinations.
Material 3 Navigation Drawers, using NavigationView
, come in Standard (persistent) and Modal (temporary with scrim) variants, but are deprecated in favor of expanded navigation rails in the Material 3 Expressive update. This guide covers implementation, accessibility, and theming for legacy use.
Using Navigation Drawers
- Add Material Components for Android and AndroidX DrawerLayout library dependencies
- Use
NavigationView
for content, withDrawerLayout
for Modal drawers - Apply
Theme.Material3.*
theme for styling - Note: Deprecated; use expanded navigation rails instead
Accessibility
- Set
android:contentDescription
on menu items and header images for TalkBack - Ensure open/close controls meet 48dp touch targets
- Support keyboard navigation with
ESC
key to close drawers - Menu items are auto-readable by accessibility services
Behavior and Configuration
- Configure menus via XML resources, headers via layouts
- Handle item selection with
setNavigationItemSelectedListener
- Use
DrawerLayout
for Modal drawer open/close with predictive back support
val drawerLayout = findViewById<DrawerLayout>(R.id.drawer_layout)
val navigationView = findViewById<NavigationView>(R.id.navigation_view)
navigationView.setNavigationItemSelectedListener { menuItem ->
menuItem.isChecked = true
drawerLayout.close()
true
}
Navigation Drawer Variants
- Standard Navigation Drawer: Persistent, coexists with content, for larger screens
- Modal Navigation Drawer: Temporary, blocks content with scrim, for mobile devices
Standard Navigation Drawer
- Permanently visible, ideal for tablets/desktops
- Uses
NavigationView
withinConstraintLayout
Standard Navigation Drawer Anatomy
Component | Description | Active State | Inactive State |
---|---|---|---|
Container | Permanent, 280dp max width, 0dp elevation | Holds active item | Holds inactive items |
Headline | Optional header text | Visible if set | Visible if set |
Label Text | Menu item titles | Highlighted with colorOnSecondaryContainer | Faded with colorOnSurfaceVariant |
Icon | Menu item icons, 24dp | Highlighted with colorOnSecondaryContainer | Faded with colorOnSurfaceVariant |
Active Indicator | Highlights active item, rounded shape | Visible, colorSecondaryContainer | Not visible |
Badge Label Text | Optional counts/status indicators | Visible if set | Visible if set |
Example
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:headerLayout="@layout/header_navigation_drawer"
app:menu="@menu/navigation_drawer"
app:layout_constraintStart_toStartOf="parent"/>
<!-- Screen content -->
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- res/menu/navigation_drawer.xml -->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/main_item"
android:title="@string/mail_subheader">
<menu>
<item
android:id="@+id/inbox_item"
android:icon="@drawable/ic_inbox_24"
android:title="@string/inbox"
android:checkable="true"/>
<item
android:id="@+id/outbox_item"
android:icon="@drawable/ic_outbox_24"
android:title="@string/outbox"
android:checkable="true"/>
</menu>
</item>
</menu>
val navigationView = findViewById<NavigationView>(R.id.navigation_view)
navigationView.setNavigationItemSelectedListener { menuItem ->
menuItem.isChecked = true
true
}
Modal Navigation Drawer
- Temporary, blocks content with a scrim
- Ideal for mobile devices
- Supports predictive back
Modal Navigation Drawer Anatomy
Component | Description | Active State | Inactive State |
---|---|---|---|
Container | Temporary, 280dp max width, 1dp elevation | Holds active item | Holds inactive items |
Headline | Optional header text | Visible if set | Visible if set |
Label Text | Menu item titles | Highlighted with colorOnSecondaryContainer | Faded with colorOnSurfaceVariant |
Icon | Menu item icons, 24dp | Highlighted with colorOnSecondaryContainer | Faded with colorOnSurfaceVariant |
Active Indicator | Highlights active item, rounded shape | Visible, colorSecondaryContainer | Not visible |
Badge Label Text | Optional counts/status indicators | Visible if set | Visible if set |
Scrim | Dims content, 60% opacity | Visible when open | Hidden when closed |
Example
<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Screen content -->
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/header_navigation_drawer"
app:menu="@menu/navigation_drawer"/>
</androidx.drawerlayout.widget.DrawerLayout>
val drawerLayout = findViewById<DrawerLayout>(R.id.drawer_layout)
val navigationView = findViewById<NavigationView>(R.id.navigation_view)
topAppBar.setNavigationOnClickListener {
drawerLayout.open()
}
navigationView.setNavigationItemSelectedListener { menuItem ->
menuItem.isChecked = true
drawerLayout.close()
true
}
Adding Header
- Add branding/info via
app:headerLayout
or programmatically - Positioned at the top of the drawer
<!-- res/layout/header_navigation_drawer.xml -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
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>
Adding Dividers and Subtitles
- Dividers auto-added between groups with unique IDs
- Submenus treated as subtitles
<!-- res/menu/navigation_drawer.xml -->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/main_item"
android:title="@string/mail_subheader">
<menu>
<item
android:id="@+id/search_item"
android:icon="@drawable/ic_search_24"
android:title="@string/search_title"
android:checkable="true"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/rotation_item"
android:icon="@drawable/ic_3d_rotation_24"
android:title="@string/3d_title"
android:checkable="true"
app:showAsAction="ifRoom"/>
</menu>
</item>
<item
android:id="@+id/labels_item"
android:title="@string/labels_subheader">
<menu>
<item
android:id="@+id/label_one"
android:icon="@drawable/ic_label_24"
android:title="@string/label_one_title"
android:checkable="true"
app:showAsAction="ifRoom"/>
</menu>
</item>
</menu>
Attributes and Usage
Element | Attribute | Related Method(s) | Default Value | Usage Description | Component Type |
---|---|---|---|---|---|
Container | android:background |
setBackground |
?attr/colorSurfaceContainerLow |
Sets container background color | All |
Container | app:elevation |
setElevation |
0dp (Standard), 1dp (Modal) | Sets container elevation | All |
Header | app:headerLayout |
inflateHeaderView , addHeaderView , getHeaderView |
null |
Sets header layout | All |
Item Text | app:itemTextColor |
setItemTextColor |
?attr/colorOnSecondaryContainer (active), ?attr/colorOnSurfaceVariant (inactive) |
Sets menu item text color | All |
Icon | app:itemIconTint |
setItemIconTintList |
?attr/colorOnSecondaryContainer (active), ?attr/colorOnSurfaceVariant (inactive) |
Sets menu item icon color | All |
Scrim | N/A | setScrimColor (DrawerLayout) |
Black, 60% opacity | Sets scrim color (Modal only) | Modal |
Styles
- NavigationView style:
Widget.Material3.NavigationView
- DrawerLayout style:
Widget.Material3.DrawerLayout
- Default theme attributes:
?attr/navigationViewStyle
,?attr/drawerLayoutStyle
Theming Navigation Drawers
- Customize colors, typography, and shapes
- Use
res/values/styles.xml
for theming
Example
<style name="Theme.App" parent="Theme.Material3.*">
<item name="colorSecondaryContainer">@color/shrine_pink_100</item>
<item name="colorOnSurfaceVariant">@color/shrine_pink_900</item>
</style>
<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="itemTextColor">@color/shrine_pink_900</item>
<item name="itemShapeFillColor">@color/shrine_pink_100</item>
</style>
Material Design Documentation
- Adheres to Material Design guidelines for Navigation Drawers
- Covers design, behavior, theming specifications
- Includes structure, accessibility, predictive back support
- Refer to Material Design documentation for full details
FAQ
What are Material 3 Navigation Drawers?
- Surfaces providing access to app destinations, deprecated for expanded navigation rails
How many variants are there?
- Two variants: Standard and Modal
When to use a Modal Drawer?
- Use for mobile devices with limited screen space
How to make them accessible?
- Set
contentDescription
on items; ensure 48dp touch targets
Can I customize appearance?
- Yes, theme via
res/values/styles.xml
How to add dependencies?
- Include Material Components and DrawerLayout libraries
Are there updates for the latest standards?
- Reflects latest Material 3 standards; deprecated for expanded navigation rails
Tags:
MDC Android