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.
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
Labels
Material 3 modal navigation drawer: closed and open
- 1
Menu button (hamburger)
Opens the drawer. Needs a name (“Menu”) and, on the web, aria-expanded that changes.
- 2
Scrim
Dims the page behind a modal drawer. Tapping it closes the drawer.
- 3
Drawer sheet
Slides in from the start edge. Gets focus when it opens and keeps it inside.
- 4
Headline
Optional title or account switcher at the top.
- 5
Destination
Icon plus label. Selecting one navigates and closes a modal drawer.
- 6
Active indicator
Marks the current page. Must match where you really are.
- 7
Badge
Unread count, e.g. 24 in Inbox. Must stay current.
- 8
Divider & section label
Groups secondary destinations like labels, Settings and Help.
Modal or standard?
| Type | Where | How it behaves |
|---|---|---|
| Modal drawer | Phones, small windows | Slides over the page with a scrim. Must be closed before you can use the page again. Like a modal. |
| Standard (permanent) drawer | Tablets, desktops | Sits 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
| Component | Best for | Visible? |
|---|---|---|
| Drawer | Many or secondary destinations | Hidden until opened (modal) |
| Bottom bar | 3–5 main areas, used often | Always on screen |
| Tabs | Sections of one screen | Always on screen |
| Bottom sheet | Actions or options for the current task | Opened 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
AndroidTap ☰. 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 ☰.
Home
Hamburger menu
WebThe button’s name and aria-expanded change with the state. Picking a page closes the menu. Try it with Tab, Enter and Esc.
Dashboard
Standard (permanent) drawer
Tablet · DesktopOn 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.
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>witharia-expandedthat switches betweenfalseandtrue, andaria-controlspointing 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
| Exit | Where | What must happen |
|---|---|---|
| Choose a destination | Everywhere | Navigate and close the drawer |
| Tap the scrim | Modal drawers | Close. The tap must not reach the page behind |
| Swipe the drawer away | iOS, Android, mobile web | Close |
| Close button (✕) / ☰ again | Web, often apps | Close |
| Esc | Web, hardware keyboards | Close |
| System Back | Android | Close the drawer first, not the screen behind |
| Route change | Web (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:
- Focus is trapped inside the drawer (focus trapFocus trapKeeping keyboard focus inside an open modal so users can't tab into the hidden page behind it.Open in glossary →). Tab must not wander through the links hidden behind the scrimScrimThe dimmed layer behind a modal or bottom sheet that blocks the page underneath.Open in glossary →.
- Scroll lock: the page behind must not scroll when you scroll the drawer or swipe on the scrim. A long drawer scrolls on its own; when it reaches the end, the page behind stays still. See Modal › Scroll lock.
- The screen reader must not read the page behind.
Dev note
On the web:aria-modal="true"orinerton the rest of the page.
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
| # | Bug | What you see | Typical severity |
|---|---|---|---|
| 1 | Nameless menu button | Screen reader says “button”; aria-expanded stays false | High (for affected users) |
| 2 | Stays open after navigating | The page changes behind the still-open menu | Medium |
| 3 | Page behind scrolls | Scrolling the menu or the scrim moves the page | Medium |
| 4 | Wrong item highlighted | “Home” is marked on every page, or nothing is | Low–Medium |
| 5 | Focus escapes | Tab goes to links behind the scrim; Esc does nothing | High (for affected users) |
| 6 | Focus lost on close | After closing, focus jumps to the top of the page | Medium |
| 7 | Back swipe opens the drawer | On iOS, swiping back from a detail screen pulls the drawer instead | Medium–High |
| 8 | Back closes the app | Android system Back closes the app instead of the drawer | High |
| 9 | Taps go through the scrim | Tapping the dimmed area also presses a button behind it | Medium |
| 10 | Broken at the breakpoint | Rotating with the drawer open leaves a scrim with no drawer, or two menus | Medium |
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.
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.
Autumn is here
Warm layers, soft knits and rain-ready jackets.
Shop the sale: up to 30% off →Accessibility inspector
- Focused
- Click into the shop and press Tab…
- Name
- –
- State
- –
- Visible
- –
- Page scroll
- 0px
- 1
Hint: Tab to the ☰ button and read the inspector, before and after opening the menu.
- 2
Hint: Open the menu and tap “Women”.
- 3
Hint: Open the menu and scroll over the menu or the dimmed area.
- 4
Hint: Go to Sale or My orders, then open the menu.
- 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 pagepositivehigh
Steps
- Open shop.example.com at 375 px wide
- Tap ☰
- 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, returnpositivehigh
Steps
- Tab to ☰ and press Enter
- Press Tab repeatedly
- Press Shift+Tab repeatedly
- 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 statepositivemedium
Preconditions
- VoiceOver or TalkBack on
Steps
- Move to the menu button
- Activate it
- 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 opennegativemedium
Steps
- Scroll the page halfway down
- Open the drawer
- Scroll over the drawer and over the scrim (wheel, trackpad, finger)
- 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 highlightedpositivelow
Steps
- Open /sale from a banner on the home page (not via the menu)
- 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 screennegativehigh
Preconditions
- iOS app with a drawer on the first screen
Steps
- Open a message from the inbox
- 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 openpositivehigh
Steps
- Open the drawer on the first screen
- 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 openedgelow
Steps
- Open the modal drawer on a tablet in portrait
- Rotate to landscape (standard drawer)
- 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-expandedlive in the Elements panel, and use the Accessibility pane to see each element’s name and role. Typedocument.activeElementin 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-expandedreflects the state andaria-controlspoints 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 getsinertor the drawer is arole="dialog"witharia-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 hasaria-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, SwiftUINavigationSplitView.
- Material modal and standard navigation drawers, or a navigation rail on bigger screens.
Dev note
ModalNavigationDrawer,DismissibleNavigationDrawer,PermanentNavigationDrawerin 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. Inspectaria-expanded,aria-controls, focus,inertand 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.A user picks "Sale" in the hamburger menu. The Sale page loads behind, but the menu stays open. What is it?
2.Which situation fits a drawer best?
3.On iOS, on a message detail screen, you swipe from the left edge and the drawer opens. Why is that a problem?
4.On a website, the hamburger button's aria-expanded is "false" while the menu is open. Who is affected?
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 ⚡