---
title: Master–Detail Drawer
slug: master-detail-drawer
kind: pattern
summary: Keep the list on screen and open the selected record in a panel beside it, so someone can inspect ten records without navigating ten times.
problem: Someone is working through a collection — reviewing signups, checking orders, triaging tickets — and needs the full record for one row, then the next, then the next. A detail page gives them the record but takes the list away, so every inspection costs a round trip and they lose their place in the queue.
family: [scan, inspect]
data_shape: [collection, tabular]
principles: [orientation, minimize-distance, progressive-disclosure]
interaction: [selection, disclosure]
density: medium
complexity: medium
status: stable
visibility: public
use_when:
  - People inspect several records in a row rather than one and stop.
  - Losing your place in the list would be expensive — a sorted queue, a filtered view, a long scroll position.
  - The detail is roughly a screenful. Ten fields and a note, not a nested workflow.
  - Comparison matters — "was the last one like this too?"
avoid_when:
  - The record has its own workflows inside it (sub-tabs, a builder, a multi-step form). Give it a page.
  - People need to link, bookmark or share the record. A drawer that does not write the URL cannot be sent to a colleague.
  - The detail genuinely needs the full canvas — a document, a map, a dashboard.
  - The list has one row. Then the list is the ceremony, not the content.
alternatives:
  - slug: drawer-vs-modal-vs-page
    when: You are not yet sure which of the three surfaces this record deserves. Start here.
  - slug: dense-operational-table
    when: People need to compare across records rather than read one deeply. Put more in the row and you may not need a drawer at all.
ask_leo: |
  Use the master–detail drawer pattern on this screen.

  - Keep the list or table exactly where it is. Selecting a row must not scroll,
    re-sort, re-filter or re-paginate it.
  - Open the selected record in a panel anchored to the right edge, 420–600px
    wide depending on the content, full height, scrolling independently of the list.
  - Mark the selected row so it is obvious which record the panel is showing.
  - Selecting another row replaces the panel content in place. Do not close and
    reopen, and do not stack panels.
  - Escape closes the panel. So does clicking outside it, and an explicit close
    button in the panel's top corner.
  - Put the selected record's id in the URL so the view can be reloaded and shared,
    and make browser Back close the panel rather than leave the page.
  - Give the panel a heading that names the record, and put its two or three most
    important facts directly under that heading before any other detail.
  - On a narrow screen, show the panel as a full-screen sheet instead of a side
    panel. Do not shrink the layout to fit both.
related:
  - title: Filterable Index with Slide-Out Detail Drawer
    url: /cookbook/filterable-index-with-detail-drawer
    summary: The Rails, Turbo and Stimulus implementation of this pattern, with the code.
  - title: Progressive Disclosure for Dense Detail Pages
    url: /cookbook/progressive-disclosure-detail-page
    summary: What to do when the record turns out to be too big for a drawer after all.
  - title: UX Principles Guide for Building Web Software
    url: /wiki/ux-principles-for-web-software
    summary: The principles this pattern applies — orientation, minimizing distance, and progressive disclosure.
---

## Anatomy

```
┌───────────────────────────────────┬──────────────────────────────┐
│ Customers            [search   ]  │ Acme Corporation        [×]  │
│                                   │                              │
│ ▸ Acme Corp          Active       │ Status   Active              │
│   Globex             Trial        │ Owner    Dana Whitfield      │
│   Initech            Active       │ MRR      $1,200              │
│   Umbrella           Churned      │ Since    March 2024          │
│   Wonka Industries   Trial        │ ─────────────────────────    │
│                                   │ Notes                        │
│   … list keeps its scroll,        │ Renewed early. Asked about   │
│     sort and filter …             │ the reporting add-on.        │
└───────────────────────────────────┴──────────────────────────────┘
  ▸ = selected row, still visible     panel scrolls independently
```

Four parts, and all four are load-bearing:

1. **The list, unmoved.** It keeps its scroll position, sort order, filters and pagination across every selection. The moment selecting a row disturbs any of those, the pattern has failed — the user is now doing navigation work again.
2. **The selection marker.** A left border, a tint, a chevron. Without it the panel is floating detail with no visible source.
3. **The panel.** Anchored to one edge, full height, its own scroll. It replaces its content on the next selection rather than closing and reopening.
4. **The exits.** Escape, click-outside, and a visible close button. Three, because people reach for different ones and the pattern must not depend on which.

## Why it works

**It removes navigation from an inspection loop.** Reviewing twelve records through detail pages costs twenty-four transitions and twelve chances to lose your place. Through a drawer it costs twelve clicks and none. That is the whole argument, and it is why the pattern earns its complexity.

**It preserves spatial context.** The list stays where the eye left it, so the user's mental model of "where am I in this queue" survives every inspection. This is the orientation principle doing real work: *where am I* is answered continuously instead of being rebuilt after each round trip.

**It is progressive disclosure with the overview still on screen.** Most disclosure patterns trade the overview for the detail. This one keeps both, which is why it suits comparison work — "was the last one like this too?" is answerable without remembering.

**It shortens the distance between the row and its detail.** The record's name and its facts sit side by side rather than a page apart, so connecting them costs a glance instead of a memory.

## Getting it wrong

The four failures worth naming, because each one looks fine in a demo and hurts in daily use:

- **The disappearing list.** The panel is modal, or takes 70% of the width, or dims the list to unreadability. Now it is a modal wearing a drawer's clothes, and the context you paid complexity for is gone.
- **No URL.** Someone finds the record that explains the problem and cannot send it to anyone. Write the id into the URL; it costs one line and turns the drawer into something shareable.
- **Back leaves the page.** The user presses Back expecting the panel to close, and lands on the previous screen with their filters gone. Push a history entry when the panel opens.
- **The drawer that grew.** Sub-tabs appear, then a nested form, then a wizard. That is the signal the record deserved a page all along. Promote it rather than widening the panel again.

## Exemplars

**Linear's issue inspector.** Selecting an issue from the list opens it beside the list, and the keyboard moves between issues without touching the mouse — the pattern's real ceiling is reached when the whole loop is keyboard-driven and the list becomes a cursor.

**Stripe's payment inspector.** A payment opens beside the ledger with the timeline of events first. The lesson worth stealing is the ordering: the panel leads with *what happened to this record over time*, because that is what someone inspecting a payment came to find out. A drawer's top 200 pixels should answer the question that made you click.

**Gmail's reading pane.** The oldest version of this pattern in daily use, and the one that proves the split: it survives because the list is a queue people work through in order, not a directory they visit occasionally.

The extractable rule from all three: **the drawer belongs to the list, not to the record.** It is a way of reading a collection. When the record starts to feel like the subject rather than the current item, it has outgrown the pattern.
