Skip to content
Bugwise
Menu
UI Components

Drawer / Hamburger Menu

A panel of destinations that slides in from the side, usually opened with the ☰ button. Learn modal and standard drawers, the hamburger debate, edge swipes vs back swipes, and the focus, scroll and "still open" bugs testers find in them.

30 min Navigation iOS · Android · Web Also called: Navigation drawer, Side menu, Hamburger menu, Off-canvas menu

You’re on a clothing shop’s website on your phone. You tap ☰, pick Sale, and… the page behind changes, but the menu is still covering it. You close it by hand. Then you scroll the menu and the page behind it scrolls too. Each of these is small, but together they make the shop feel broken, and some shoppers simply leave.

Three short lines (☰) hide a whole navigation system. A drawer has to open and close in many ways, move focus correctly, lock the page behind, show where you are, and stay out of the way of the system’s own gestures. Let’s learn how a good one behaves.

What is a drawer?

A navigation drawer is a panel of destinations that slides in from the side of the screen (the left in left-to-right languages, the right in Arabic or Hebrew). It’s usually opened by the menu button, the three-line icon people call the hamburger (☰). On the web the same thing is called a hamburger menu, side menu or off-canvas menu.

It holds destinations that don’t fit in, or don’t deserve, a permanent spot on screen: all the categories of a shop, mail folders and labels, Settings, Help, Legal.

Anatomy

Material 3 modal navigation drawer: closed and open

  1. 1

    Menu button (hamburger)

    Opens the drawer. Needs a name (“Menu”) and, on the web, aria-expanded that changes.

  2. 2

    Scrim

    Dims the page behind a modal drawer. Tapping it closes the drawer.

  3. 3

    Drawer sheet

    Slides in from the start edge. Gets focus when it opens and keeps it inside.

  4. 4

    Headline

    Optional title or account switcher at the top.

  5. 5

    Destination

    Icon plus label. Selecting one navigates and closes a modal drawer.

  6. 6

    Active indicator

    Marks the current page. Must match where you really are.

  7. 7

    Badge

    Unread count, e.g. 24 in Inbox. Must stay current.

  8. 8

    Divider & section label

    Groups secondary destinations like labels, Settings and Help.

TypeWhereHow it behaves
Modal drawerPhones, small windowsSlides over the page with a scrim. Must be closed before you can use the page again. Like a modal.
Standard (permanent) drawerTablets, desktopsSits next to the content, no scrim. Often collapsible to a narrow rail of icons.

Many apps switch between the two at a breakpointBreakpointA screen width where a responsive layout changes, for example from one column to two.Open in glossary →: a modal drawer on a phone, a standard drawer on a tablet in landscape. Test both sides of the breakpoint, and what happens when you rotate or resize while the drawer is open.

How it differs from similar components

ComponentBest forVisible?
DrawerMany or secondary destinationsHidden until opened (modal)
Bottom bar3–5 main areas, used oftenAlways on screen
TabsSections of one screenAlways on screen
Bottom sheetActions or options for the current taskOpened on demand

Designs & variants

Open and close each drawer in every way you can think of: tap, swipe, Esc, keyboard only.

Inbox

  • Anna · Flight to Lisbon
  • Shop · Your parcel is on its way
  • Mila · Lunch Friday?
  • Bank · Statement ready
  • Gym · New class times
  • Leo · Photos from Sunday

Modal navigation drawer

Android

Tap ☰. The drawer slides over the page with a scrim. Close it by choosing a destination, tapping the scrim, swiping it left or pressing Esc. Focus returns to ☰.

ScrimSwipe to closeFocus moves in
shop.example.com/
Threadline

Home

Hamburger menu

Web

The button’s name and aria-expanded change with the state. Picking a page closes the menu. Try it with Tab, Enter and Esc.

aria-expandedaria-controlsCloses on navigation

Dashboard

Standard (permanent) drawer

Tablet · Desktop

On wide screens the drawer stays next to the content, with no scrim. Collapse it to a rail of icons to give the content more room.

Always visibleNo scrimCollapses to a rail

When to use it

  • There are many destinations (more than five), like the categories of a shop or the folders of a mail app.
  • The destinations are secondary or used rarely: Settings, Help, Legal, account switching.
  • On wide screens, as a standard drawer that’s always visible.
  • On mobile websites, where the desktop’s top navigation doesn’t fit.

Good and bad uses

The hamburger debate

Hiding navigation saves space, but people use what they can see. A well-known Nielsen Norman Group study (2016) found that people used hidden navigation much less often than visible navigation, found things more slowly, and rated the tasks as harder. The effect was strongest on desktop, where hiding the menu wasn’t even necessary.

There’s another side, and you should know it too:

  • Today almost everyone recognizes ☰ as “menu”. The problem is out of sight, out of mind, not confusion.
  • A drawer is a reasonable home for secondary destinations, as long as the main ones are visible.
  • On a small phone, a long list of shop categories simply has to go somewhere.

The usual middle ground: keep the 3–5 most important destinations visible (a bottom bar or tabs) and put the rest behind ☰.

Main areas visible, extras in the menu

Home, Search, Orders and Account are one tap away. ☰ holds categories, Help and Settings.

Everything behind ☰

To check an order, users must remember that Orders exists and open the menu every time.

How a good drawer behaves

Opening

  • The menu button must have a name (“Menu” or “Open navigation menu”).

    Dev note
    On the web it’s a real <button> with aria-expanded that switches between false and true, and aria-controls pointing to the menu.

  • Edge swipe. Some apps let you pull the drawer out from the edge of the screen. That edge is shared with the system:

    • iOS: the left edge swipe means Back. If a drawer also listens to it, one of the two loses. The safe rule: edge swipe opens the drawer only on the first screen of the app, where there’s nothing to go back to.
    • Android (gesture navigation): a swipe from either side edge is system Back. Since Android 10, a drawer can still be pulled out by pressing and holding at the edge, then dragging. A quick swipe must stay Back.

    See Gestures › Edge swipes belong to the system for the details.

  • Focus moves into the drawer, usually to the current destination or the first link, so keyboard and screen readerScreen readerSoftware that reads the screen aloud for blind and low-vision users, like VoiceOver or TalkBack.Open in glossary → users know it opened.

Closing

ExitWhereWhat must happen
Choose a destinationEverywhereNavigate and close the drawer
Tap the scrimModal drawersClose. The tap must not reach the page behind
Swipe the drawer awayiOS, Android, mobile webClose
Close button (✕) / ☰ againWeb, often appsClose
EscWeb, hardware keyboardsClose
System BackAndroidClose the drawer first, not the screen behind
Route changeWeb (single-page apps)Close, even when the page changed some other way (a link inside the page, browser Back)

After closing, focus returns to the menu button. Otherwise keyboard users are thrown back to the top of the page, or into nothing.

While it’s open

A modal drawer is a dialog, so the rules from Modal apply:

Showing where you are

The current destination is highlighted (Material: a pill-shaped indicator) and, on the web, marked with aria-current="page". Test it on every page, including pages reached without the drawer: from a link in the page, a deep link, a search result or browser Back. A classic web bug: matching the URL with “starts with”, so Home (/) matches every page.

Common bugs

#BugWhat you seeTypical severity
1Nameless menu buttonScreen reader says “button”; aria-expanded stays falseHigh (for affected users)
2Stays open after navigatingThe page changes behind the still-open menuMedium
3Page behind scrollsScrolling the menu or the scrim moves the pageMedium
4Wrong item highlighted“Home” is marked on every page, or nothing isLow–Medium
5Focus escapesTab goes to links behind the scrim; Esc does nothingHigh (for affected users)
6Focus lost on closeAfter closing, focus jumps to the top of the pageMedium
7Back swipe opens the drawerOn iOS, swiping back from a detail screen pulls the drawer insteadMedium–High
8Back closes the appAndroid system Back closes the app instead of the drawerHigh
9Taps go through the scrimTapping the dimmed area also presses a button behind itMedium
10Broken at the breakpointRotating with the drawer open leaves a scrim with no drawer, or two menusMedium

Try it: the drawer lab

Open the drawer with ☰ and from the edge. Close it every way: scrim, swipe, Esc, System Back, choosing a folder. Then open a message and swipe from the left edge on both platforms. Switch Edge swipe opens the drawer to Every screen and try again.

9:41

Inbox

Platform

Edge swipe opens the drawer

The shaded strip is the edge zone. Drag from it to the right with your finger or mouse. On Android with gesture navigation, a quick swipe from the edge is system Back. Press and hold at the edge first, then drag, to pull the drawer out. Also try Tab and Esc while the drawer is open.

Event log

  • Opens, closes, swipes and Back presses appear here…

Find the bug

This mobile clothing shop has a hamburger menu with five bugs. Explore it like a tester:

  • Open the menu and pick a page. Look at the menu and at what’s highlighted.
  • Scroll with the menu open (mouse wheel or finger over the menu and the dimmed area). Watch Page scroll in the inspector.
  • Use only the keyboard: Tab to the menu button, Enter, then Tab and Esc.
  • Watch the accessibility inspector below the shop: what is focused, its name and its state.

🐞 Bug hunt: Threadline mobile shop

This demo has 5 hidden bugs. Explore it like a tester, then check your findings.

Found0/5
shop.example.com/

Accessibility inspector

Focused
Click into the shop and press Tab…
Name
–
State
–
Visible
–
Page scroll
0px
  1. 1

    Hint: Tab to the ☰ button and read the inspector, before and after opening the menu.

  2. 2

    Hint: Open the menu and tap “Women”.

  3. 3

    Hint: Open the menu and scroll over the menu or the dimmed area.

  4. 4

    Hint: Go to Sale or My orders, then open the menu.

  5. 5

    Hint: Open the menu with Enter, then press Tab a few times, then Esc.

How to test it

Checklist

Drawer test checklist

0 of 14 checked

Example test cases

TC-DRW-001Menu closes after choosing a page

Steps

  1. Open shop.example.com at 375 px wide
  2. Tap ☰
  3. Tap "Women"

Expected result

The Women page opens, the menu and scrim are gone, and "Women" is highlighted the next time the menu opens.

TC-DRW-002Keyboard: open, trap, close, return

Steps

  1. Tab to ☰ and press Enter
  2. Press Tab repeatedly
  3. Press Shift+Tab repeatedly
  4. Press Esc

Expected result

Focus moves into the menu, cycles only through menu items, Esc closes the menu, and focus is back on ☰.

TC-DRW-003Screen reader announces name and state

Preconditions

  • VoiceOver or TalkBack on

Steps

  1. Move to the menu button
  2. Activate it
  3. Move back to the button

Expected result

Before: "Menu, button, collapsed". After opening: "expanded" (or "Close menu"). Menu items are read, the page behind is not.

TC-DRW-004Scroll lock while the drawer is open

Steps

  1. Scroll the page halfway down
  2. Open the drawer
  3. Scroll over the drawer and over the scrim (wheel, trackpad, finger)
  4. Close the drawer

Expected result

The page behind never moves. After closing, it is at the same position as before.

TC-DRW-005Current page is highlighted

Steps

  1. Open /sale from a banner on the home page (not via the menu)
  2. Open the drawer

Expected result

Only "Sale" is highlighted and has aria-current="page". "Home" is not.

TC-DRW-006iOS back swipe on a detail screen

Preconditions

  • iOS app with a drawer on the first screen

Steps

  1. Open a message from the inbox
  2. Swipe from the left edge to the right

Expected result

The app goes back to the inbox. The drawer does not open.

TC-DRW-007Android system Back with the drawer open

Steps

  1. Open the drawer on the first screen
  2. Press system Back (button, then gesture)

Expected result

The drawer closes. The app stays open on the same screen.

TC-DRW-008Resize across the breakpoint while open

Steps

  1. Open the modal drawer on a tablet in portrait
  2. Rotate to landscape (standard drawer)
  3. Rotate back

Expected result

No leftover scrim, no duplicate menu, the current page still highlighted, the page usable.

Tip: click a test case to expand it.

Tools

  • Web: in DevTools, use the device toolbar for phone widths, check aria-expanded live in the Elements panel, and use the Accessibility pane to see each element’s name and role. Type document.activeElement in the Console to see where focus really is.
  • Screen readers: VoiceOver on Mac (Cmd+F5) and iPhone, TalkBack on Android, NVDA on Windows.
  • Android Emulator: test system Back in gesture and 3-button navigation (Settings › System › Gestures › System navigation), rotate with the toolbar, and switch the language to Arabic to check the right-to-left drawer.
  • iOS Simulator: drag from the very left edge with the mouse to test the back swipe on every screen that has a drawer.

Accessibility

  • Button: a real button with a name (“Menu”, “Open navigation menu”) and an expanded state that reflects the drawer. Changing the label to “Close menu” while open is fine too.
    Dev note
    aria-expanded reflects the state and aria-controls points to the menu.
  • Focus: moves into the drawer on open, stays inside while open, returns to the button on close.
    Dev note
    On the web, the rest of the page gets inert or the drawer is a role="dialog" with aria-modal="true".
  • Landmark: the list of links is a navigation landmark with a label, and the current link is announced as the current page.
    Dev note
    A <nav> with a label (e.g. aria-label="Main"); the current link has aria-current="page".
  • Not gesture-only: every drawer opened by a swipe also has a visible button, and every drawer closed by a swipe also has ✕, Esc and Back. WCAGWCAGThe Web Content Accessibility Guidelines, the main international standard for accessibility.Open in glossary → 2.5.7 (Dragging Movements) asks that dragging always has a simple tap alternative.
  • Touch targetsTouch targetThe area of the screen that responds to a tap, which should be large enough for a finger.Open in glossary →: ☰ and each item at least 44×44 pt / 48×48 dp. Destination rows in Material drawers are 56 dp tall.
  • Visible focus on every item, and enough contrast for the current-page indicator (3:1) and labels (4.5:1).

Mobile vs web

  • No native hamburger on iPhone. If an app has one, it’s custom: test the left edge back swipe on every screen, VoiceOver, and the Dynamic Type sizes.
  • iPad: a sidebar works like a standard drawer and can be shown or hidden. Test it in Split View and Slide Over, where the window is narrow.
    Dev note
    UISplitViewController, SwiftUI NavigationSplitView.
  • Material modal and standard navigation drawers, or a navigation rail on bigger screens.
    Dev note
    ModalNavigationDrawer, DismissibleNavigationDrawer, PermanentNavigationDrawer in Compose.
  • System Back must close the drawer first. With predictive back, the drawer should slide along with the gesture and only close on release.
  • Gesture navigation reserves both edges for Back: the drawer opens by button, or press-and-hold at the edge.
  • Usually a <button> plus a <nav> panel, built by hand or with a UI library. Inspect aria-expanded, aria-controls, focus, inert and scroll lock.
  • Single-page apps: check that every route change (menu link, in-page link, browser Back) closes the menu.
  • Responsive: the hamburger appears below a breakpointBreakpointA screen width where a responsive layout changes, for example from one column to two.Open in glossary →. Resize across it with the menu open, and check that desktop navigation and the hamburger never show at the same time.
  • Mobile Safari: check that the page behind doesn’t scroll when you swipe on the scrim, and that the menu isn’t hidden behind the browser toolbar.

Check your understanding

Quick quiz

0/5 answered · 0 correct

  1. 1.A user picks "Sale" in the hamburger menu. The Sale page loads behind, but the menu stays open. What is it?

  2. 2.Which situation fits a drawer best?

  3. 3.On iOS, on a message detail screen, you swipe from the left edge and the drawer opens. Why is that a problem?

  4. 4.On a website, the hamburger button's aria-expanded is "false" while the menu is open. Who is affected?

  5. 5.The drawer is open. You press Tab and focus lands on a product link behind the dimmed area. What is missing?

Key takeaways

  • A modal drawer slides over the page with a scrim; a standard drawer sits next to the content on wide screens.
  • Hidden navigation gets used less. Keep the main destinations visible and put secondary or many destinations in the drawer.
  • Closing must work every way: choosing a destination, scrim, swipe, ✕, Esc, Android Back, and every route change on the web.
  • While open: focus moves in and is trapped, the page behind doesn’t scroll, and on close focus returns to ☰.
  • The current page is highlighted correctly on every page, and the ☰ button has a name and a live aria-expanded.
  • Edge swipes compete with iOS back swipe and Android system Back. The system gesture must win on deeper screens.

Finished this page?Nice work, this page is complete!

Mark it as done to track your progress. It's saved in this browser, no account needed.

Its review cards are now in Bites ⚡
Esc

Type to search the whole site.