{"slug":"modal-maze","meta":{"title":"Modal Maze","slug":"modal-maze","kind":"anti-pattern","summary":"A modal opens a modal opens a modal — each one blocking the context the next one needs, until nobody can see the record they are supposedly editing.","problem":"You open a record in a modal, click Edit inside it, get a second modal, need to pick a client, get a third. The page underneath — the one with the information you need to answer the question — has been blocked three times over by the software that is asking you the question.","family":["inspect","act"],"principles":["orientation","progressive-disclosure"],"status":"stable","visibility":"public","related":[{"title":"Drawer vs Modal vs Page","url":"/patterns/drawer-vs-modal-vs-page","summary":"The decision that prevents this — three surfaces, three promises about context."},{"title":"Master–Detail Drawer","url":"/patterns/master-detail-drawer","summary":"The usual right answer for the record that got put in a modal."}]},"body":"## How you get here\n\nModals are the cheapest way to add a screen. They need no route, no layout\ndecision and no thought about where the thing lives. So the first one appears\nreasonably — a short confirm, a small form — and then each subsequent need is\nsolved the same way, because the mechanism is already there.\n\nThe second modal is not a new mistake. It is the **first modal admitting it was\ncarrying too much**.\n\n## How to recognise it\n\n- Two or more overlays stacked, with two dimmed layers behind.\n- Escape closes the wrong one, or closes all of them and loses everything typed.\n- A modal has grown tabs, or a stepper, or its own scrollbar.\n- Someone needs a value from the page behind and has to close, look, reopen, and\n  retype.\n- The modal cannot be linked to, so \"look at this record\" is a set of\n  instructions rather than a URL.\n- The browser Back button leaves the page entirely instead of closing the top\n  layer.\n\n## Why it fails\n\nA modal makes exactly one promise: **this is the only thing that matters right\nnow.** Stacking them breaks the promise on the first repetition — clearly the\nthing underneath also mattered, because you are still holding it.\n\nThe specific damage is to context. A modal deliberately blocks the page, so\nanything you need from that page is unreachable. In a single modal that is an\nacceptable trade for a bounded task. In a stack it is the reason the person is\nstuck, and it produces the worst workaround in internal software: opening the\nsame record in a second browser tab to read what the modal is covering.\n\n## The way out\n\n1. **Never open a modal from a modal.** Treat this as a hard rule; it is the one\n   that keeps the rest honest.\n2. When you want to, **promote the first modal to a page**. It has outgrown the\n   surface, and the second modal is the evidence.\n3. If the parent list must stay visible, that is a\n   [drawer](/patterns/master-detail-drawer), not a modal — and a drawer can host\n   a genuine modal above it for a bounded confirm.\n4. **Pick one surface per kind of object** and use it everywhere. Most mazes\n   grow in products where the same record opens three different ways.\n5. **Give anything with depth a URL.** If people need to share it, it was never\n   a modal.\n\n## The one legitimate stack\n\nA confirmation over a form — \"discard your changes?\" — is a genuine second\nlayer, because it is *about* the first one and it is bounded, immediate and has\none way out. That is the exception, and it is the only one worth allowing.\n\n## The test\n\nCount the dimmed layers on screen. More than one, and something on the stack\ndeserved a page. Then check whether Escape closes only the top layer and Back\ndoes something sensible — if not, people are already losing work.\n"}