Navigation drawer

The navigation drawer component is a slide-in menu that lets users navigate to various sections of your app. Users can activate it by swiping from the side or tapping a menu icon.

Consider these three use cases for implementing a Navigation Drawer:

  • Content organization: Enable users to switch between different categories, such as in news or blogging apps.
  • Account management: Provide quick links to account settings and profile sections in apps with user accounts.
  • Feature discovery: Organize multiple features and settings in a single menu to facilitate user discovery and access in complex apps.

In Material Design, there are two types of navigation drawers:

  • Standard: Share space within a screen with other content.
  • Modal: Appears over the top of other content within a screen.
An example of a Material Design 3 navigation drawer in light and dark mode.
Figure 1. An example of a navigation drawer.

Example

You can use the ModalNavigationDrawer composable to implement a navigation drawer.

Use the drawerContent slot to provide a ModalDrawerSheet and provide the drawer's contents, as in the following example:

ModalNavigationDrawer(
    drawerContent = {
        ModalDrawerSheet {
            Text("Drawer title", modifier = Modifier.padding(16.dp))
            HorizontalDivider()
            NavigationDrawerItem(
                label = { Text(text = "Drawer Item") },
                selected = false,
                onClick = { /*TODO*/ }
            )
            // ...other drawer items
        }
    }
) {
    // Screen content
}

ModalNavigationDrawer accepts a number of additional drawer parameters. For example, you can toggle whether or not the drawer responds to drags with the gesturesEnabled parameter as in the following example:

ModalNavigationDrawer(
    drawerContent = {
        ModalDrawerSheet {
            // Drawer contents
        }
    },
    gesturesEnabled = false
) {
    // Screen content
}

Control behavior

To control how the drawer opens and closes, use DrawerState. You should pass a DrawerState to ModalNavigationDrawer using the drawerState parameter.

DrawerState provides access to the open and close functions, as well as properties related to the current drawer state. These suspending functions require a CoroutineScope, which you can instantiate using rememberCoroutineScope. You can also call the suspending functions in response to UI events.

val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
val scope = rememberCoroutineScope()
ModalNavigationDrawer(
    drawerState = drawerState,
    drawerContent = {
        ModalDrawerSheet { /* Drawer content */ }
    },
) {
    Scaffold(
        floatingActionButton = {
            ExtendedFloatingActionButton(
                text = { Text("Show drawer") },
                icon = { Icon(Icons.Filled.Add, contentDescription = "") },
                onClick = {
                    scope.launch {
                        drawerState.apply {
                            if (isClosed) open() else close()
                        }
                    }
                }
            )
        }
    ) { contentPadding ->
        // Screen content
    }
}

Create groups within a navigation drawer

The following snippet shows how to create a detailed navigation drawer, with sections and dividers:

@Composable
fun DetailedDrawerExample(
    content: @Composable (PaddingValues) -> Unit
) {
    val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
    val scope = rememberCoroutineScope()

    ModalNavigationDrawer(
        drawerContent = {
            ModalDrawerSheet {
                Column(
                    modifier = Modifier.padding(horizontal = 16.dp)
                        .verticalScroll(rememberScrollState())
                ) {
                    Spacer(Modifier.height(12.dp))
                    Text("Drawer Title", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.titleLarge)
                    HorizontalDivider()

                    Text("Section 1", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.titleMedium)
                    NavigationDrawerItem(
                        label = { Text("Item 1") },
                        selected = false,
                        onClick = { /* Handle click */ }
                    )
                    NavigationDrawerItem(
                        label = { Text("Item 2") },
                        selected = false,
                        onClick = { /* Handle click */ }
                    )

                    HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp))

                    Text("Section 2", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.titleMedium)
                    NavigationDrawerItem(
                        label = { Text("Settings") },
                        selected = false,
                        icon = { Icon(Icons.Outlined.Settings, contentDescription = null) },
                        badge = { Text("20") }, // Placeholder
                        onClick = { /* Handle click */ }
                    )
                    NavigationDrawerItem(
                        label = { Text("Help and feedback") },
                        selected = false,
                        icon = { Icon(Icons.AutoMirrored.Outlined.Help, contentDescription = null) },
                        onClick = { /* Handle click */ },
                    )
                    Spacer(Modifier.height(12.dp))
                }
            }
        },
        drawerState = drawerState
    ) {
        Scaffold(
            topBar = {
                TopAppBar(
                    title = { Text("Navigation Drawer Example") },
                    navigationIcon = {
                        IconButton(onClick = {
                            scope.launch {
                                if (drawerState.isClosed) {
                                    drawerState.open()
                                } else {
                                    drawerState.close()
                                }
                            }
                        }) {
                            Icon(Icons.Default.Menu, contentDescription = "Menu")
                        }
                    }
                )
            }
        ) { innerPadding ->
            content(innerPadding)
        }
    }
}

Key points about the code

  • Populates the drawerContent with a Column containing sections, dividers, and navigation items.
  • ModalDrawerSheet provides Material Design styling for the drawer.
  • HorizontalDivider separates sections within the drawer.
  • ModalNavigationDrawer creates the drawer.
  • drawerContent defines the content of the drawer.
  • Inside the ModalDrawerSheet, a Column arranges the drawer elements vertically.
  • NavigationDrawerItem composables represent individual items in the drawer.
  • The Scaffold provides the basic structure of the screen, including the TopAppBar.
  • The navigationIcon in the TopAppBar controls the drawer's open and close state.

Result

The following image shows how the drawer appears when opened, with sections and items displayed:

A detailed navigation drawer with two sections, each with multiple labeled items and icons.
Figure 2. A navigation drawer opened with two nested groups.

Additional resources

Content and code samples on this page are subject to the licenses described in the Content License. Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.

Last updated 2026-03-30 UTC.