Agent docs

11 · A record detail

Showing one record's detail: a preview, a drill-in, everything about the row.

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.

ChooseWhenWhy
Peek panelthe surrounding context must stay visible, for example a run's log beside a part detailit is an in-flow column, not an overlay
Modalthe detail IS the task and context can be obscuredthe surrounding list is not needed while you work
Full pagethe surface is a destination in its own rightrare; 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 alongDefaultLawDeviate when
1Surface choiceper the tree above, decided explicitly10 §A1yes, 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
2Drawer claimone drawer, claimed; a second peek does not open alongside10 §A2no
3Modal identitystore-driven, string-identified, rendered locally at the callsite10 §A3no; modals are NOT centrally mounted, unlike toasts
4Modal chromecomposed and quiet10 §A4no
5Title anatomyglyph, then primary over secondary10 §A9no
6Horizontal insetexactly one owner, and it is the shell10 §A10no; compounding insets is a measured violation
7Scroll ownershipthe body scrolls, the shell does not10 §A13no
8Confirmuse the componentized Confirm; a raw confirm is drift, not an exception to copy10 §A5no; speedway's four raw call sites are the thing to migrate, not precedent
9Confirm timingthe action starts before the modal closes, and its outcome is reported10 §A5, 10 §A8no
10Empty and error insidematch the page's own empty and error states10 §A11no
11Copy affordancesattach to the data plane, never the control plane10 §A12no
12Perceived speedmount the frame immediately, do not wait on the fetch to render anything10 §A6no
13Loading insideskeleton the values, keep everything known at open time real04 §A3no
14Entry pointone way in per record, and the list agrees with it06 §A2no; two ways into the same detail is the row-click bug class
15Return pathclosing returns to the list without losing position or selection06 §A3see the ?hl= divergence in AP-10
16Mutation feedbacksettles into a toast owned by a component that survives the close02 §A6, 10 §A8no
17Tooltipsdo not wrap a component that carries its own10 §A7-adjacentno; 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 rowHow this surface does it
1, surface choicemodal, because the part detail is the task
3, identitystring-identified, opened via openModal from each list
14, entry pointthe eye icon is the single way in; the row click does something else
16, feedbackpushAlert.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-gutter in its own stylesheet. Row 7, and a live kit tension rather than an app defect.
@versable-git/ui · reference, canon, and method, read in place