Dismiss handler: scrim tap, Esc, or the close button.
edge
DrawerEdge
'left'
Which vertical edge the panel is anchored to + slides from.
mode
DrawerMode
'overlay'
'overlay' = the drawer role (scrim + focus trap); 'inline' = the persistent nav-rail role (no scrim, app stays live). 'modal' is a deprecated alias of 'overlay'. Default 'overlay'.
title *
string
n/a
Accessible title shown in the header (carries the dialog/region name).
subtitle
string
n/a
Optional supporting line under the title.
footer
React.ReactNode
n/a
Optional right-aligned action row pinned to the panel footer.
stage *
HTMLElement | null
n/a
The contained stage element, which gates rendering so the drawer never escapes it.
children *
React.ReactNode
n/a
Panel body: a nav list (left) or detail content (right).
Parameter
Type
Default
Description
drawerState
DrawerState
rememberDrawerState(Closed)
Open/closed state. DrawerValue.Open / Closed; animate via drawerState.open() / close().
drawerContent *
@Composable ColumnScope.() -> Unit
n/a
The sheet content, typically a ModalDrawerSheet wrapping NavigationDrawerItems.
modifier
Modifier
Modifier
External modifier applied to the whole drawer container.
gesturesEnabled
Boolean
true
Whether the edge swipe + scrim drag can open/close the drawer.
scrimColor
Color
DrawerDefaults.scrimColor
The modal scrim tint over the content. (Resolve to color.scrim.)
content *
@Composable -> Unit
n/a
The main screen behind/beside the drawer (the trailing lambda).
selected *
Boolean
n/a
NavigationDrawerItem: the selected row gets the cyan container + indicator.
onClick *
() -> Unit
n/a
NavigationDrawerItem: row activation (usually navigates, then closes the drawer).
SwiftUI has no single “Drawer” view; the edge-anchored panel is built from two
standard primitives: NavigationSplitView (the collapsible left sidebar) and the
.inspector modifier (the right detail drawer, macOS 14+). State comes from the
bindings below.
Style
Type
Default
Description
NavigationSplitView
View
n/a
The left navigation drawer: a sidebar column + a detail column. The sidebar collapses to an overlay on compact widths.
columnVisibility
Binding<NavigationSplitViewVisibility>
n/a
Drives the sidebar: .all (open) / .detailOnly (collapsed) / .automatic.
.inspector(isPresented:)
ViewModifier
n/a
The right inspector / detail drawer (macOS 14+). isPresented is a Binding<Bool> that slides it in from the trailing edge.
.inspectorColumnWidth
ViewModifier
n/a
Sets the inspector’s min / ideal / max width.
.navigationTitle
ViewModifier
n/a
The drawer/region accessible name, shown at the top of the sidebar.
Cross-platform drift (tracked for reconciliation)
Distinct from its catalog siblings: bottom-sheet rises from the bottom edge,
dialog is a centered card, and app-shell / sidebar are the permanent rail.
A drawer is the overlay (or push panel) anchored to a vertical edge. The shipped
apps don’t yet use a true overlay drawer. These are the real divergences:
Android ships on Material 3 (the ModalNavigationDrawer API above is
available), but currently presents navigation as a bottom sheet
(AvatarSettingsSheet, raised from the avatar), not a left nav drawer. The
Compose code is the intended drawer; the live app is a sheet.
Voice deliberately hand-rolls its left sidebar (a translucent floating
panel over the facet background) rather than using NavigationSplitView, because
the native split view paints an opaque material the in-app background can’t show
through. It has no right inspector yet. The Swift code documents the standard
primitives; Voice’s sidebar is a custom view.
Selection treatment: Voice’s selected row is accent @ 16% fill + accent @ 45% border (mirrored in the web demo). Compose’s NavigationDrawerItem uses
Material’s own selected container. One selection expression needs to win.