Modal
A window that sits on top of the screen and blocks everything else until you answer it. Learn the platform variants, the many ways to close one, and the focus, scroll and data-loss bugs testers find every week.
You tap Delete account in a food delivery app and the screen dims. A small box asks “Delete account?” with Cancel and Delete. You can’t scroll, you can’t tap the menu, you have to decide. That box is a modalModalA window that appears on top of the page and blocks the content behind it until it is closed.Open in glossary →.
Modals look like the simplest thing in an app: a box with a title and two buttons. But they control what the user is allowed to do, they guard destructive actions, and they hold unsaved data. When they misbehave, people delete things by accident, lose what they typed, or get stuck. Let’s learn them properly.
What is a modal?
A modal is a window that appears on top of the current screen and blocks interaction with everything behind it until the user responds or dismisses it. The word comes from “mode”: while it’s open, the app is in a special mode where only the modal works.
You’ll usually see one used to:
- Confirm a destructive or important action: Delete 3 photos?, Cancel your subscription?, Discard changes?
- Ask for a quick decision: Allow notifications?, Choose a delivery time.
- Do a short, focused task without leaving the page: edit a delivery address, add a card, write a review.
- Tell the user something they must acknowledge: Your session expired. Please log in again.
Anatomy
- 1
Scrim (backdrop)
A dark layer over the page. It shows that the page behind is blocked until you finish.
- 2
Container
The dialog surface itself. It must fit the screen, even on a small phone with large text.
- 3
Title
A short question or statement: "Delete 3 photos?", not "Are you sure?".
- 4
Supporting text
Explains the consequence. Long content must scroll inside the container.
- 5
Dismissive action
Cancel / Keep editing. Closes the dialog without changing anything.
- 6
Confirming action
The verb from the title ("Delete"). Red when it destroys data.
- 7
Close button
Optional X (common on web). Behaves exactly like Cancel.
How it differs from similar components
The key questions are: does it block the screen? and does the user have to respond? Using a blocking component for something that didn’t need it is a valid usability finding.
| Component | Blocks the screen? | Needs a response? | Typical use |
|---|---|---|---|
| Alert dialog | Yes | Yes | Short, urgent decision: “Delete account?” |
| Dialog | Yes | Usually | A small task or choice: pick a date, rename a file |
| Full-screen dialog | Yes (covers it) | Save or close | A longer task on a phone: new event, new address |
| Modal bottom sheet / action sheet | Yes | Pick an option or dismiss | A list of actions or options: Share, Sort by |
| Popover / menu | Partly (closes on outside tap) | No | Extra options next to a button |
| Toast / snackbarToastA short, temporary message that appears briefly and disappears on its own, like 'Message sent'.Open in glossary → | No | No (optional action) | Brief feedback: “Message archived · Undo” |
| Banner / inline message | No | No (optional action) | Persistent status or warning on the page |
Dev note
Apple calls the small centered one an alert and the bottom list an action sheet; larger ones are sheets. Google’s Material Design calls them dialogs (basic and full-screen) and bottom sheets. On the web you’ll hear modal, dialog, popup and lightbox. In bug reports, use the name your team uses, and say which kind it is.
Designs & variants
Each platform has its own look and its own rules for how a modal can be closed. The chips under each demo list the exits that should work.
Every demo works. Open each one and try every way out: the buttons, tapping outside, Esc, and (on the sheet) dragging the handle down.
Albums
Alert
iOSSmall, centered, max two side-by-side buttons. Tapping outside does nothing: the user must choose. Destructive actions are red, Cancel is bold.
Albums
Action sheet
iOSSlides up from the bottom with a list of choices and a separate Cancel. On iPad it becomes a popover next to the button.
Settings
Basic dialog
Android · Material 3Rounded 28dp surface, text buttons on the right: dismissive first, confirming last. The system Back gesture closes it.
Settings
Full-screen dialog
Android · Material 3For longer tasks on phones (forms, multiple fields). X closes, Save confirms. Closing with unsaved input should ask before throwing it away.
Your cart
Modal dialog
WebUsually a white card with an X, a backdrop and footer buttons. Built by hand far too often, so focus and Esc handling are frequent bugs.
Settings
Modal bottom sheet
Android · iOS · WebEasy to reach with one thumb. iOS has sheets too (with detents, medium and large). Test the swipe-down gesture and what happens to typed data.
When to use it
A modal is a good choice when:
- The user is about to do something destructive or hard to undo and must confirm it.
- The app can’t continue without an answer (permission, expired session, required choice).
- The task is short and focused, and leaving the current page would lose the user’s context.
- The information is critical and must not be missed.
Good and bad uses
Every modal interrupts. A good rule: interrupt only for decisions, not for news.
Clear question, clear verbs
Delete 3 photos?
They'll be removed from all your devices.
The title names the action and the button repeats the verb. The destructive button is red.
Vague question, Yes / No
Are you sure?
Do you want to continue?
Sure about what? “Yes” and “No” force the user to re-read the question, and nothing signals danger.
Non-blocking feedback
Success needs no decision. A snackbarToastA short, temporary message that appears briefly and disappears on its own, like 'Message sent'.Open in glossary → confirms it and lets the user carry on.
A modal just to say “done”
Success!
An extra tap for nothing. Users learn to hit “OK” without reading, and then they also skip the dialogs that matter.
Inline for non-urgent info
The user sees it, but can finish what they came to do.
Popups on app start
Enjoying Foodly?
Blocking the user the moment they open the app, before they’ve done anything, is pure friction.
How a good modal behaves
Most modal bugs aren’t about how it looks. They’re about behavior: which button does what, how you get out, and where focus and scrolling go. These are the rules to test against.
Destructive confirmations
- The title is a specific question with the action in it: Delete “Lisbon 2025”?, not Are you sure?
- The confirm button repeats the verb: Delete, Remove, Cancel order. Not OK or Yes.
- Destructive actions look destructive: red text (iOS, Material) or a red button (web).
- Button order follows the platform. iOS two-button alerts put Cancel on the left and the destructive action on the right. Material puts the dismissive action left and the confirming action right. On the web, follow the design system and be consistent across the whole product.
- The safe option is the default. Pressing Enter or having initial focus should never trigger Delete in a destructive dialog. Focus the least destructive button.
- Confirming happens once. The button shows progress and ignores extra taps (a double submitDouble submitA bug where an action runs twice because the user tapped or clicked twice quickly.Open in glossary → can delete twice or charge twice).
Every way to close a modal
| Exit | iOS | Android | Web | What must happen |
|---|---|---|---|---|
| Cancel / Close button | ✓ | ✓ | ✓ | Closes, changes nothing |
| X icon | Sheets, full-screen | Full-screen dialogs | Very common | Same as Cancel |
| Tap outside (scrim) | Sheets yes, alerts no | Yes by default | Usually | Same as Cancel, or ignored. Never confirm |
| Esc key | With a hardware keyboard | With a hardware keyboard | ✓ | Same as Cancel |
| System Back | — | ✓ (button or gesture) | Browser Back: team decision | Closes the dialog first, not the screen behind |
| Swipe down | Sheets | Bottom sheets | Mobile web sheets | Same as Cancel |
Focus: in, trapped, and back
Keyboard and screen readerScreen readerSoftware that reads the screen aloud for blind and low-vision users, like VoiceOver or TalkBack.Open in glossary → users can’t “see” the dim layer. They rely on focus:
- Focus moves in when the modal opens, to the first field or the safest button, so the screen reader starts reading the dialog.
- Focus is trapped inside. Tab and Shift+Tab cycle through the modal’s controls only. This is a focus trapFocus trapKeeping keyboard focus inside an open modal so users can't tab into the hidden page behind it.Open in glossary →. If focus escapes, users end up on invisible buttons behind the scrim.
- Focus returns to the element that opened the modal when it closes. Otherwise keyboard users are thrown back to the top of the page.
Scroll lock
While a modal is open, the page behind it should not scroll. Test by scrolling with a mouse wheel, a trackpad and a finger over the dialog and over the scrim. A classic bug on iOS Safari: the page behind scrolls when you swipe on the dim area. If the modal content is long, the modal itself should scroll, with its buttons still reachable.
Nested modals
A modal opening another modal (Edit address → Delete this address?) is a warning sign in design. If it exists, test it hard: Esc and Back should close only the top one, focus should return to the dialog underneath (not the page), and the scrims shouldn’t stack into a black screen.
Small screens and the open keyboard
On a phone, a centered dialog with a form often breaks when the keyboard appears: the Save button ends up behind the keyboard, or the dialog is taller than the screen and can’t scroll. Test on the smallest supported phone, in landscape, with the largest text size, and with the keyboard open. Good apps switch to a full-screen dialog or a sheet on small screens.
Common bugs
| # | Bug | What you see | Typical severity |
|---|---|---|---|
| 1 | Outside tap confirms or loses data | Tapping the dim area deletes, submits, or throws away typed text | High |
| 2 | Can’t close it | Esc, Android Back or swipe-down do nothing; the user is stuck | Medium–High |
| 3 | Background still works | Taps go through the scrim, or the page behind scrolls | Medium |
| 4 | Focus escapes | Tab reaches links behind the modal; screen reader reads the page, not the dialog | High (for affected users) |
| 5 | Focus not returned | After closing, focus jumps to the top of the page | Medium |
| 6 | Double confirm | Fast double tap fires two requests: two orders, two deletions, an error after success | High |
| 7 | Doesn’t fit the screen | Long text or large fonts push the buttons off-screen with no scrolling | High |
| 8 | Hidden by the keyboard | Save or Continue is behind the on-screen keyboard | Medium |
| 9 | Reopens or stacks | The modal comes back after closing, or opens twice on a double tap | Medium |
| 10 | Wrong or vague buttons | “OK / Cancel” for a delete, destructive button not red, safe option not default | Medium |
Try it: close it every way
Switch good behaviors off one by one, open the dialog, and try to get out with Esc, a click outside, Tab and the scroll wheel. Then switch to phone and tap a field to open the keyboard.
🧪 Close-it-every-way playground
Switch behaviors off, then open the dialog and try to escape it with the keyboard, the mouse and the scroll wheel. The log shows what a tester would notice.
Problems with these settings
This dialog behaves well. Now switch a setting off and see what breaks.
Event log
- Open the dialog to start…
Find the bug
This Android account screen has six bugs around its two dialogs: Discard changes? (edit your profile, then tap the back arrow) and Delete account? (the red row). Explore it like a tester:
- Try every way out of each dialog: buttons, the dim area, and System Back.
- Tap things you can still see behind the dialog.
- Tap buttons twice, fast, and watch the network log.
- Turn on Large text.
🐞 Bug hunt: Account settings
This demo has 6 hidden bugs. Explore it like a tester, then check your findings.
Account
Maya Lopez
Coffee, cycling and spicy ramen.
Device
Network log
- Requests will appear here…
- 1
Hint: Change your name, tap the back arrow, then tap the dark area.
- 2
Hint: Open either dialog and press System Back.
- 3
Hint: Open Delete account and tap Delete twice quickly. Watch the network log.
- 4
Hint: With the delete dialog open, tap the bottom navigation.
- 5
Hint: Turn on Large text and open Delete account.
- 6
Hint: Discard your edits, then open Edit profile again.
How to test it
Checklist
Modal test checklist
0 of 13 checked
Example test cases
TC-MOD-001Confirming deletes the account oncepositivehigh
Preconditions
- User is logged in
- Network log or proxy is recording
Steps
- Open Account
- Tap "Delete account"
- Tap "Delete"
Expected result
Exactly one DELETE request is sent. The button shows progress and is disabled. The user lands on the "Account deleted" screen.
TC-MOD-002Double tap on the confirm buttonedgehigh
Steps
- Open "Delete account?"
- Tap "Delete" twice within 1 second
Expected result
Only one request is sent and the user sees the success result, not an error.
TC-MOD-003Every dismissal path cancelsnegativehigh
Steps
- Open "Delete account?"
- Close it with: Cancel, tap outside, System Back (Android), Esc (web / hardware keyboard)
- Check the account after each attempt
Expected result
Each path closes the dialog and the account still exists. No request is sent.
TC-MOD-004Unsaved changes are protectednegativehigh
Steps
- Open Edit profile
- Change the name to "Maya L."
- Tap Back
- Tap outside the "Discard changes?" dialog
Expected result
The dialog closes, the user stays on Edit profile and "Maya L." is still in the field.
TC-MOD-005Background is blocked while the modal is opennegativemedium
Steps
- Open any modal
- Tap the bottom navigation and list items visible behind the scrim
- Scroll over the scrim and over the dialog
Expected result
Nothing behind the modal reacts and the page behind does not scroll.
TC-MOD-006Keyboard focus is trapped and returned (web)positivemedium
Steps
- Tab to "Change address" and press Enter
- Press Tab 10 times, then Shift+Tab 10 times
- Press Esc
Expected result
Focus starts in the first field, cycles only through the dialog's controls, and returns to "Change address" after Esc.
TC-MOD-007Dialog fits with the largest text sizeedgemedium
Preconditions
- Smallest supported phone
- Font size set to maximum (Android Settings › Display › Font size / iOS Larger Text)
Steps
- Open "Delete account?"
Expected result
All text is readable. If content is too tall, the body scrolls and both buttons remain visible and tappable.
TC-MOD-008Form dialog with the keyboard openedgemedium
Preconditions
- Phone in portrait, then landscape
Steps
- Open "Edit delivery address"
- Tap the Street field so the keyboard opens
- Try to tap Save without closing the keyboard
Expected result
Save is visible and works in both orientations (e.g. full-screen dialog with Save in the top bar).
TC-MOD-009Screen reader announces the dialogpositivemedium
Preconditions
- VoiceOver / TalkBack is on
Steps
- Activate "Delete account"
- Swipe right through the dialog, then keep swiping
Expected result
The title is read first ("Delete account?, alert"), then the text and buttons. Swiping never reaches elements behind the dialog.
Tip: click a test case to expand it.
Accessibility
- Role and name. The dialog is announced as a dialog, with its title. Native iOS and Android dialogs get this for free; custom ones often don’t.
Dev note
On the web, use the native<dialog>element withshowModal(), orrole="dialog"(role="alertdialog"for urgent confirmations) plusaria-modal="true"andaria-labelledbypointing to the title. - Focus management. Move focus in on open, trap it inside (focus trapFocus trapKeeping keyboard focus inside an open modal so users can't tab into the hidden page behind it.Open in glossary →), and return it to the trigger on close. Make the page behind inert so screen readers can’t wander there.
- Esc closes on the web, and the Back gesture closes on Android. A visible Close or Cancel button must always exist: not everyone can tap outside or press Esc.
- Contrast. Text needs 4.5:1, button shapes need 3:1 against their background, and the dialog must stand out from the page (an edge with 3:1 contrast, or a clear scrim). Red destructive text must still reach 4.5:1.
- Touch targetsTouch targetThe area of the screen that responds to a tap, which should be large enough for a finger.Open in glossary → of at least 44×44 pt (iOS) / 48×48 dp (Android), including the X icon, which is often too small.
- Large text. Content must scroll rather than clip at the biggest Dynamic TypeDynamic TypeThe phone setting that lets users make text bigger or smaller across apps.Open in glossary → and Android font sizes.
- Don’t rely on color alone to mark the destructive action: use the verb in the label too.
Mobile vs web
- Alerts: centered, title + message + up to two side-by-side buttons (more stack vertically). Tapping outside does not close them.
- Action sheets: slide up from the bottom with a separate Cancel; on iPad they appear as a popover next to the button.
- Sheets: cards that slide up, can have detents (medium / large) and close with a swipe down. Test swipe-down with unsaved data: apps can block it and ask first.
Dev note
Alerts:UIAlertController/ SwiftUI.alert. Action sheets:.confirmationDialog. Sheets:.sheet. - Test with VoiceOver, Larger Text, iPhone SE size, landscape, and a hardware keyboard on iPad (Esc / ⌘ + .).
- Material 3 basic dialogs (rounded 28 dp, text buttons on the right) and full-screen dialogs (X, title, Save) for longer tasks on phones.
- Back (button or edge-swipe gesture) must close the dialog first. By default, tapping outside closes a dialog too, but developers can turn that off.
- Modal bottom sheets have a drag handle and close with a swipe down.
- Watch for rotation: a dialog can disappear, duplicate or lose its input when the activity is recreated.
- Test with TalkBack, maximum font size and display size, and small devices.
- Custom
divmodals often get focus and scroll wrong.Dev note
Prefer the native<dialog>withshowModal(): it gives Esc handling, top-layer rendering and an inert background. - Check Esc, click outside, the X, and focus with Tab. Inspect roles and
aria-modalin DevToolsDevToolsDeveloper tools built into browsers for inspecting pages, network traffic and errors.Open in glossary →. - Test scroll lock with wheel, trackpad and touch, especially on iOS Safari.
- Test responsive behavior: at 360 px wide and with the mobile keyboard open, can you still reach every button?
- Decide what browser Back does with an open modal. Either way, it shouldn’t lose the user’s data.
Check your understanding
Quick quiz
0/5 answered · 0 correct
1.A user edits their profile, taps Back, sees "Discard changes?" and taps the dark area outside it. What should happen?
2.Which confirmation is the best for deleting an album?
3.On the web, you press Tab inside a modal and focus lands on a link in the page behind it. What is missing?
4.You tap "Pay" twice quickly in a confirmation dialog and get charged twice. What kind of bug is this?
5.Which of these does NOT need a modal?
Key takeaways
- A modal blocks the screen until the user responds. Use it for decisions and destructive actions, not for news or success messages.
- Destructive dialogs need a specific title, a verb on the confirm button, destructive styling and the safe option as default.
- Test every exit: buttons, X, tap outside, Esc, System Back, swipe down. All of them mean cancel, and none may silently lose typed data.
- While open: background blocked and not scrolling, focus trapped, and focus returned on close.
- Classic bugs: double confirm, dialogs that don’t fit small screens, large text or the keyboard, and dialogs that reopen.
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 ⚡