You were asked to show one record's detail, a preview, a drill-in, a "click the row and see everything about it". This is what that request brings along.
Audience: an agent (or person) asked to build a detail, preview, or drill-in.
The first row of the bundle is the one that decides everything after it, and it is the one most often decided by accident. Answer it before writing anything.
Traits involved: 10 overlays, 06 tables, 04 loading and states, 03
status language, 02 buttons.
Row zero: peek, modal, or page#
The canon rules this at 10 §A1. It is not a taste call, but it is also not a
ban: owner ruling D1 lets a surface break the tree "IF the rule-breakage leads
to a better and more consistent UX, with good reasoning". Deviation is
legitimate and never free. The surface that deviates records its reason in its
own doc, and the reason names the UX the break buys. What the ruling retired was
per-surface discretion exercised silently, not discretion itself.
| Choose | When | Why |
|---|---|---|
| Peek panel | the surrounding context must stay visible, for example a run's log beside a part detail | it is an in-flow column, not an overlay |
| Modal | the detail IS the task and context can be obscured | the surrounding list is not needed while you work |
| Full page | the surface is a destination in its own right | rare; diagnostic pages are the named exception |
Speedway has retired a full page for duplicating a dialog. It removed its part page because "it duplicated the parts table's preview dialog". If you are reaching for a page, check first that you are not rebuilding a modal that already exists.
The bundle#
| # | Comes along | Default | Law | Deviate when |
|---|---|---|---|---|
| 1 | Surface choice | per the tree above, decided explicitly | 10 §A1 | yes, under ruling D1, when the break buys better and more consistent UX AND the surface's own doc records why; an unstated choice is the defect |
| 2 | Drawer claim | one drawer, claimed; a second peek does not open alongside | 10 §A2 | no |
| 3 | Modal identity | store-driven, string-identified, rendered locally at the callsite | 10 §A3 | no; modals are NOT centrally mounted, unlike toasts |
| 4 | Modal chrome | composed and quiet | 10 §A4 | no |
| 5 | Title anatomy | glyph, then primary over secondary | 10 §A9 | no |
| 6 | Horizontal inset | exactly one owner, and it is the shell | 10 §A10 | no; compounding insets is a measured violation |
| 7 | Scroll ownership | the body scrolls, the shell does not | 10 §A13 | no |
| 8 | Confirm | use the componentized Confirm; a raw confirm is drift, not an exception to copy | 10 §A5 | no; speedway's four raw call sites are the thing to migrate, not precedent |
| 9 | Confirm timing | the action starts before the modal closes, and its outcome is reported | 10 §A5, 10 §A8 | no |
| 10 | Empty and error inside | match the page's own empty and error states | 10 §A11 | no |
| 11 | Copy affordances | attach to the data plane, never the control plane | 10 §A12 | no |
| 12 | Perceived speed | mount the frame immediately, do not wait on the fetch to render anything | 10 §A6 | no |
| 13 | Loading inside | skeleton the values, keep everything known at open time real | 04 §A3 | no |
| 14 | Entry point | one way in per record, and the list agrees with it | 06 §A2 | no; two ways into the same detail is the row-click bug class |
| 15 | Return path | closing returns to the list without losing position or selection | 06 §A3 | see the ?hl= divergence in AP-10 |
| 16 | Mutation feedback | settles into a toast owned by a component that survives the close | 02 §A6, 10 §A8 | no |
| 17 | Tooltips | do not wrap a component that carries its own | 10 §A7-adjacent | no; stacking two is a live defect in both apps |
The trap in row 12#
10 §A6 is about perceived speed, and the failure it prevents is specific.
Speedway measured a file-preview dialog that rendered nothing for a full network
round trip, 820ms of dead air, which read to users as the modal being broken.
The fix was mounting a spinner the moment the chip is clicked, reaching visible
in 37ms under injected latency.
The general rule: the frame is known at click time, so the frame renders at click time. Only the values wait.
The trap in row 9#
A confirm modal that closes before its action starts leaves the user with no evidence anything happened. Walmart hit this and the fix is recorded in its code: "The confirm modal is gone before the request settles; the promise toast is the only affordance covering the gap."
So a confirm that triggers async work owes a toast, and the toast must be owned
by something that outlives the modal. This is the same ownership lesson as
10 §A8, where toast state died with the component that pushed it.
Worked example: walmart part preview#
walmart-mvp/frontend/src/features/parts/PartPreviewModal.tsx.
A modal reached from every parts list. Good for studying rows 1, 3 and 14 together, because the same modal is entered from four different surfaces and they had to agree.
| Bundle row | How this surface does it |
|---|---|
| 1, surface choice | modal, because the part detail is the task |
| 3, identity | string-identified, opened via openModal from each list |
| 14, entry point | the eye icon is the single way in; the row click does something else |
| 16, feedback | pushAlert.promise on each async action, spinner into result |
Two known gaps at this surface, both recorded rather than hidden. The modal
takes only a part id, so its identifier is undefined until the fetch resolves,
which 10 §A9's Loading note tracks as satisfying the ruling's negative half,
nothing bones, without its positive half. Separately, the same modal still
hand-rolls its title with its own CopyButton at PartPreviewModal.tsx:830-849
instead of using ModalTitle's identifier and onIdentifierCopied props. So
this example is a good study of the recipe's rows and a poor model for row 5.
Copy its structure, not its title.
Where the do-nots live#
Assembled in P1 of the knowledge-docs run. The verified ones for this recipe:
- A confirm modal closing before its async action starts, so the user sees no evidence the action began. Row 9.
- A component that carries its own tooltip wrapped in another tooltip, stacking two. Row 17.
- A modal whose panes scroll internally while the kit assumes page-level
scrolling, which walmart works around by overriding
scrollbar-gutterin its own stylesheet. Row 7, and a live kit tension rather than an app defect.