Reader Stacks

How to Create a Drawer in Flutter

A Drawer only opens automatically if the Scaffold has an AppBar — without one, the swipe-to-open gesture works, but the hamburger icon that most users actually tap for it never appears.

How to Create a Drawer in Flutter

Flutter's Drawer widget provides a slide-in side navigation panel — assigning it to a Scaffold's drawer property is most of the work, though a couple of details around the hamburger icon and closing behavior are worth understanding.

A basic drawer

Scaffold(
  appBar: AppBar(title: const Text('My App')),
  drawer: Drawer(
    child: ListView(
      padding: EdgeInsets.zero,
      children: [
        const DrawerHeader(
          decoration: BoxDecoration(color: Colors.deepPurple),
          child: Text('Menu', style: TextStyle(color: Colors.white, fontSize: 24)),
        ),
        ListTile(
          leading: const Icon(Icons.home),
          title: const Text('Home'),
          onTap: () {
            Navigator.pop(context); // close the drawer
            // navigate to home
          },
        ),
        ListTile(
          leading: const Icon(Icons.settings),
          title: const Text('Settings'),
          onTap: () {
            Navigator.pop(context);
            // navigate to settings
          },
        ),
      ],
    ),
  ),
  body: const Center(child: Text('Main content')),
)

Assigning a Drawer to the Scaffold's drawer property automatically adds a hamburger menu icon to the AppBar — but only if an AppBar is actually present; without one, the drawer can still be opened by swiping from the screen edge, but there's no tappable icon for it.

Closing the drawer after tapping a menu item

onTap: () {
  Navigator.pop(context);
  Navigator.pushNamed(context, '/settings');
}

Navigator.pop(context) here closes the drawer itself (the drawer counts as a route on the navigation stack) — this needs to happen before or alongside navigating to the new screen, or the drawer stays open, incorrectly overlapping the newly navigated-to content.

A drawer with a user profile header

UserAccountsDrawerHeader(
  accountName: const Text('Alex Johnson'),
  accountEmail: const Text('alex@example.com'),
  currentAccountPicture: const CircleAvatar(
    backgroundImage: NetworkImage('https://example.com/avatar.jpg'),
  ),
  decoration: const BoxDecoration(color: Colors.deepPurple),
)

UserAccountsDrawerHeader is a purpose-built alternative to the plain DrawerHeader specifically for showing a logged-in user's name, email, and avatar — a common enough pattern that Flutter provides this dedicated widget rather than requiring it to be built manually every time.

A drawer on the right side, instead of the left

Scaffold(
  endDrawer: Drawer(
    child: ListView(children: const [/* ... */]),
  ),
)

endDrawer, rather than drawer, opens from the trailing (right, in a left-to-right layout) edge of the screen instead — a common pattern for a secondary panel like filters or notifications, while the primary navigation drawer stays on the leading edge.

Opening the drawer programmatically, without user interaction

final GlobalKey _scaffoldKey = GlobalKey();

Scaffold(
  key: _scaffoldKey,
  drawer: Drawer(child: /* ... */),
)
_scaffoldKey.currentState?.openDrawer();

Assigning a GlobalKey<ScaffoldState> to the Scaffold allows opening the drawer programmatically (from a custom button rather than the automatic hamburger icon, for example) — necessary since there's no direct method to open a drawer without a reference to its Scaffold's state.