Browse all of Kata

The detail screen

Source docs/design/patterns/detail.mdMarkdown

On this page

One record, in full. The second most common shape in the app, after the list.

Part of the Konjo design language. The laws in the spine apply here unless this chapter contradicts them.

A detail screen is what a list row promised. Someone tapped a name, an event, a session, a request — they arrived with a specific question and the screen's job is to answer it before they scroll.

There are twelve-plus of these in src/, and until now they had two sentences of guidance between them.

The formula

(insets.top + spacing.tight)
‹ Back                                  44pt target, no title in the bar
                                     ↕16
BROWN BELT · 3RD KYU                      eyebrow · text.secondary
Ana Torres                                display 34/800
Joined Mar 2024 · 47 classes              caption 13 · text.secondary
                                     ↕20
[ Log attendance ]                        one filled primary, hugs left
                                     ↕24
DETAILS                                   eyebrow, on the page
┌──────────────────────────────────────┐
│ Next test          Sep 14        › │   white card; 2 rows, so no hairlines —
│                                      │   12pt between them. Six or more rows
│ Waiver             Signed          │   get hairlines, inset to the text edge.
└──────────────────────────────────────┘
                                     ↕24
RECENT                                    eyebrow
┌──────────────────────────────────────┐
│ Tuesday class · 6:30pm             │
└──────────────────────────────────────┘

Eyebrow → title → meta → primary action → content. The identifier or category is an eyebrow above the title, never a chip beside it — Linear's ENG-2486 pattern. A chip beside a title competes with it; an eyebrow above frames it.

The title is the subject, not the screen

"Ana Torres", not "Student detail". "Tuesday 6:30pm class", not "Class". The person already knows what kind of thing they tapped; what they need is which one. A detail screen whose title names the screen type has wasted its loudest element.

The title is display, and like every screen title it is chrome: it does not spend the loud block budget. What it does mean is that nothing else on the screen needs to be loud. A detail screen does not get a hero block — the record is the content, and putting an inverted slab above it means scrolling past the answer to reach the answer. So a detail screen normally spends zero of its loud budget, which is legal and correct.

The meta line

One line, caption, text.secondary, facts separated by ·. It carries what someone would say out loud after the name: how long, how many, when. Not every field the record has — that is what the sections are for.

If the meta line needs two lines, it is not a meta line, it is a section.

One primary action, above the fold

The single thing this person most likely came to do, as the one filled primary. Everything else — edit, share, remove, message — goes into the header's overflow or lives at the bottom of the relevant section as a text link.

Never a row of equal-weight buttons under the title. Three outlined buttons side by side is the shape of a screen whose designer could not decide, and the person reading it now has to.

If there is genuinely no primary action, there is no button. A read-only record is a legitimate screen.

Content sections

  • eyebrow on the page, then a white card. Group with space and a label, not a bordered box inside a bordered box.
  • Rows inside the card, hairlines inset to the text edge. Five or fewer rows: no hairlines at all, just 12pt between them.
  • Row height is a floor, never a fixed height. A one-line label/value row is minHeight 44; a two-line row (title over caption) is minHeight 64, with the caption 4pt under its title. This said 2pt, which is a layout gap written with the one value L2 reserves for optical correction — 4 is the smallest gap the ramp actually offers. Fixed heights clip at large text sizes — see accessibility.
  • Label left, value right, both in text.primary. They are equals: the label says what you are reading and the value says it. Separate them by weight, not colour — label rowTitle, value body. Do not grey the label to make the value pop; a row whose metadata outweighs its subject is anti-pattern territory.
  • Order sections by what gets looked at, not by how the data is modelled. The database's column order is never the answer.
  • A section with nothing in it does not render. No "None", no empty card. Its absence is the information. The exception is a section whose emptiness is actionable — a missing waiver is worth a row saying so.

Loading a detail screen

The person tapped a row they could already see, so you already know the title, and often the subtitle. Render them immediately from the list's data and load only the sections. A spinner covering a name the app already had in memory is a self-inflicted wound.

  • Header and title: instant, from the row.
  • Sections: skeleton at the final height, or nothing under a second.
  • A section that fails loads its own inline error and retry. One failed section never takes down the screen — see states.

A state's action inherits the weight of what it replaced. This is the rule that resolves the budget: a section that fails or is empty sits inside a screen whose primary is still on screen, so its retry is a bordered secondary — the screen has already spent its one filled primary. A whole screen that fails renders nothing else, so its retry is the filled primary. Same anatomy, different weight, and the budget holds either way.

The same logic settles a section-scoped empty state: if the action it would offer is already on screen, it offers none — text only, in flow — because the same destination twice in one viewport is worse than a missing button. An empty "Recent" section under a live "Log attendance" button says what goes there and stops.

Destructive actions

Never in the header, never adjacent to the primary action, never a red button floating above the fold. A destructive action lives at the bottom of the screen, past the content, as a text link in the screen's red role — and it arms on first tap, fires on second. See serious actions.

Never

  • A title that names the screen type instead of the record.
  • A hero block.
  • Three buttons of equal weight under the title.
  • Every field the record has, in schema order.
  • An empty section rendered as "None".
  • A full-screen spinner over data you already had.
  • Delete sitting next to the primary action.