I opened the detail view for a single item to check one thing: whether it was waiting on me. Above the fold sat a status card, a row of tuning sliders, a block of key dates, a related-items list, attached artifacts, a history log, and a metadata footer. All of it stacked, all of it accurate, none of it answering the question I came with. I had to read the entire screen to find one word.
The honest version of “I redesigned this view tonight” is “I committed it four times in two hours and the last commit only changed how a divider looks.” That is what the git log says I did between 21:55 and 23:42 one Thursday evening on a side project. By the end the page showed four things at the top and buried the rest under a collapsible labeled “Details.” Four commits to get there, and the last one wasn’t even about what to hide. It was about making the thing you click to unhide it stop looking like a button.
I want to walk through the four commits because progressive disclosure gets talked about like a decision you make once. It isn’t. It’s a convergence. You take three or four passes at the same screen, and each pass moves the line between “primary” and “buried” a little, and you don’t actually know where the line goes until you’ve pushed something across it and felt the urge to pull it back.
Commit 1: the list, not the detail
The night started one level up, in the list view. Each row used to render a little cluster of muted metadata: the item’s types joined with commas, an optional domain, an optional “value” badge, and a relative timestamp from formatDistanceToNow. Four competing bits of grey text per row, flex-wrapped so they reflowed on narrow screens into something that looked like a search-result footer.
I replaced all of it with one function, getSubtitle(item), that returns a single string. If the item is waiting on me, it says “Waiting on you.” Waiting on someone else, “Waiting on them.” Otherwise it falls back to the relative time, “3 days ago.” One sentence that answers the only question you actually ask while scanning a list: is this on me, and how stale is it?
The types and the domain and the value badge didn’t get deleted. They got relocated. Which is the part everyone skips when they say “simplify the UI.” You’re not removing information. You’re moving it to where the question that needs it actually gets asked. And the place that question gets asked is the detail view, which is where the rest of the night went.
Commit 2: strip the status card to four things
The detail view’s status card was the worst offender. It had the state icon and label, the waiting info, a state-select dropdown, a row of tuning sliders, the key dates, related items, artifacts, the history log, and the metadata. All of it, stacked, above the fold.
This commit cut the card down to four things: the state icon and label, the waiting info, and the state-select. Everything else, the sliders, the dates, the related list, the artifacts, the history, the metadata, went into a Details collapsible that defaults to closed. That one commit touched 165 lines added and 145 removed on a roughly 310-line file. More than half the file moved, and the net line count barely changed, because the work wasn’t adding or deleting, it was relocating. Same instinct as the list-row change, one level deeper.
The four things that stayed share a property: they answer “what state is this in, and what’s the one thing I might do about it right now.” State, waiting, and the select that lets you change state. Everything I buried answers a question you have occasionally, on purpose, when you’ve decided to dig in. That is the actual line, and it has nothing to do with important versus unimportant. The sliders are important. You just don’t consult them on every glance.
Commit 3: the header was lying too
So far the toggle was a button. Tap it, the Details section expands. Fine, but the header above the status card still carried the item’s types, its domain, and its intent, right next to the title. Which meant I had buried metadata in the card and then left a different pile of it in the header.
This commit pulled the header back to title plus a back button plus a delete button. Nothing else. The types, domain, and intent followed the rest of the metadata down into Details. And the toggle itself got promoted from a small button to a full-width row, because by now it had real weight behind it. It wasn’t hiding one extra field anymore. It was the seam between “the four things you came for” and “everything else about this item.” A small button undersells a seam like that.
This is the pass where the line got tested. The first time I moved intent into Details it felt wrong, because intent is closer to “primary” than to “buried” for some item types. I left it buried anyway, because the alternative was a special case in the header, and a special case is how you end up back at the wall of stuff. The line you draw has to be a line, not a per-field negotiation, or it doesn’t hold.
Commit 4: the affordance is the design
The last commit changed almost nothing about what was hidden. It restyled the toggle.
It had been a button sitting next to a Separator component. This commit turned it into a real divider: a horizontal line on each side flanking a chevron and the word “Details,” full width, no button chrome. I also deleted the now-unused Separator import, because the divider had absorbed its job.
This is the commit I’d defend hardest, and it’s the one that looks most like fiddling. A button says “this is a control, click me to do a thing.” A section divider with a chevron says “this is a seam in the page, and there’s more below it.” Those are different promises. With a button, hiding everything behind it reads as “we tucked some controls away.” With a divider, the same hidden content reads as “this is the boundary of the page, and the rest is one level down if you want it.” Same content, same toggle behavior, completely different story about what the page is.
I spent a whole commit on horizontal lines and a chevron, because the hard part of progressive disclosure was never deciding what to hide. It was making the page admit honestly that it had hidden something.
Related
- Trading Badge Soup for One Human Sentence: the list-row simplification that feeds the same “move it, don’t delete it” instinct
- ‘Newest First’ Is a Re-Priority Problem, Not an ORDER BY: another UI surface that needed a rethink of what information belongs at the top level
- Trade, or Play for Both? Turning a Silent Overwrite Into a Decision Modal: making an implicit choice explicit in the UI, same information-hierarchy reasoning
- Routing Logic That Does Work on the Way In: Redirect, Auto-Select, or Prompt: choosing what to surface at each decision layer before the user ever sees a form
- When AI Makes Analysis Cheap, Your Decision UI Becomes the Bottleneck: the same question of what belongs at the top layer when the underlying analysis is already done