Theme
Customize the design system

Every control starts at the preset. Change one and every preview on the site follows, on this page and the next, until you reset it.

Contrast

Text against what it sits on. Below 4.5:1 fails WCAG AA for body text — the check a reviewer runs on any surface that takes a tone.

Waiting for the first preview to report its palette.

Corners

Sets all three radii at once. The individual values are under Geometry.

Brand 5

The accent seam an app actually brands itself through. Change these and you have made the decision a real `DesignTokens.graphite(...)` call makes.

Geometry 15

Square or rounded, and how heavy every line is. The radius row above the controls sets all three corners at once, because "what does square feel like" is one decision rather than three numbers.

Surfaces 17

Everything the app is painted ON — the ground behind the content (the frame paints it too), the cards over it, the well inset in a card, and the washes that show state.

Bands 10

The rail's head and the view bar beside it (one band across the top at 960 and wider), a pushed screen's bar, the compact bar and the compact nav bar — the band's fill, its rule, its hover and active faces, the resting field box on it, and the ink and accent control that sit on it. The rail's tree and its footer stay on the ground.

Text and controls 11

The ink ramp, the control outlines and the field's focus halo. Every pair the panel can break is watched by a contrast badge above.

Status 7

The three voices that mean something — danger, caution and ok — each as a foreground and a surface wash, danger with a border as well.

Data 5

The default pin head, its glyph and its halo, and the group bands. A pin's category color comes from the palette, named in the theme seed.

Map 11

The basemap's roles — land, water, parks, roads and their casings, buildings, labels — and the pending pin's gray. A raster basemap keeps its own imagery; these paint the map's plate and any kit-drawn map.

Scrollbars 6

Every scroller's bar: the thumb at rest and while hovered or dragged, the strip it rides, and the desk bar's thickness, side gap and corners. The desk half shows only while a fine pointer is attached; at touch the platform's own overlay keeps its size.

Advanced 6

Real controls that are not decisions — motion durations, the focus ring offset, the touch floor. Opens collapsed on purpose.

Take it with you

The Dart that reproduces what you are looking at. It is a real constructor call, because the configurator edits a real preset — what you copy is what an app can paste.

Screens

Detail

Reach for this for one record in full — mediaHeader: and fieldLayout: shape it, and it stays generic over the record type. It OPENS at large: the two-up split (960 and up) and the fields grid's third track (1200 and up) both show by default — paneAtEnd swaps which side the fixed pane takes. Start with sectionNav either way; it is a view-type swap rather than a setting, and tabs, jump and the plain stack are three different screens.

Spec of record: design-system/components/data/DetailView.d.ts

22
Knobs

Live

Real widgets, built from the real kit. Turn a knob and it rebuilds; the theme bar above applies the design system's own tokens — including anything you changed under Customize — and the device selector uses the same sizes the golden baselines gate on, so what you see here is what CI holds the widget to.

Press Focus on any preview to take it to the full window — at a desktop width that renders most devices at 1:1, which is when the widget's own controls become clickable. The bar always states the device and the scale, so a shrunk preview says it is shrunk. Esc leaves.

screen_detail
Knobs
Theme
Assembly

Which nav the compact posture mounts — the drawer behind the hamburger, or a bottom bar.

The primary tier, and on a records destination the ONLY loud action the bar's neighborhood has. The scaffold renders it in the thumb zone at every window class; a screen never places it itself.

Actions in the drawer's own footer. The drawer carries them at EVERY window class — at 960 and wider it exists only because they do, since the expanded shell otherwise mounts a standing inline rail instead.

Shows when you open the drawer — the hamburger below 960, an edge swipe at 960 and wider, where the rail head's menu button toggles the rail instead. The actions sit in the drawer's own footer; the resting frame is identical either way. — press Focus to make the preview interactive.

The app's identity mark, and nothing else — it never opens a picker. At 960 and wider it sits beside the menu button in the rail's head at the same place in both postures, overhanging the collapsed rail so the bar beside it steps in. Below 960 the drawer's header band states it.

The scope — one value of the app's own kind (here an Area) — as the FIRST item of the bar's subtitle, ahead of the meta. With a picker it is a quiet text button with a chevron; on a phone the whole title block opens the picker as a bottom sheet. A pushed record's bar shows it read-only.

Global commands with no page ("Send feedback", "Help") pinned in the rail's footer under the footer destinations — the same row as a destination, but never lit and never counted in the destination index.

An organization's or partner's logo at the very bottom of the rail and the drawer — identity, never a control. Collapsed it shows its compact square, or nothing when the host gives none.

Swaps which side the fixed pane takes.

The status mark's tone; none is the plain word. blocked is the filled danger tag — the one status that asks someone to act.

Which SURFACE this detail view is. destination mounts it as the lit destination's body under the shell's own view bar. pushed is the record pushed INSIDE that destination: the rail stays with Records still lit, and the record's own bar takes the view bar's row — a back affordance, this record's name as the title, its own secondary action row and its sync control, last. Below 960 it is the only bar, and the bottom bar and the Fab step aside. `paneActions` is destination's alone, since pushed docks nothing. The distinction is not cosmetic: it decides what may rest in the bar, and it is the answer `/new-screen` forces before any screen is written.

This record's secondary actions, one row per action. Rendered through `AppActionBar`, so the fourth and beyond FOLD into the trailing ⋯ at `kAppBarDirectActionCap` — add a fourth and watch it happen. An `overflow` row goes straight to the menu without waiting to be pushed there.

Shows when you set `hosting` to pushed — a DESTINATION's bar rests as leading, title, search and sync and nothing else, so these have nowhere to go until this is a record surface — press Focus to make the preview interactive.

View

tabs mounts one section at a time (counts ride every tab, so unrendered is never hidden); jump keeps one scroll and lands a section at the row, and is the plain stack whenever every section already fits (add sections to see its row); none is the plain stack.

Independent of sectionNav. plain titles each block in the label role between hair rules (the pane's default), framed makes the header and every section a card on the ground (the page's), band is a 48 title-role head row with no card — never tinted.

stacked is label over value in an auto-fill grid; inline is a fixed key column, one field per hairline row; inlineAligned end-aligns data-font values so digits line up.

WHICH sections the record has, and in what order — the arrows move one. `general` is the `groups` kind: several labeled runs under one heading, and the tier the tabs posture needs, since a tab spends the section level. `what` renders in the full pane only.

The two-track section grid, 1 or 2. Clamped to 1 under tabs — the tab already split the content.

Shows when you set hosting to pushed — on destination the view is a docked pane, and the section grid measures its own box — press Focus to make the preview interactive.

0 leaves the measure uncapped.

Empty fields step aside behind a note row that says how many and offers them back.

Slots

ONE knob, because the two header shapes are mutually exclusive. Both render the framed glyph placeholder here — the spec's own blank-ref contract, so the preview needs no reachable image.

The key figures under the title and meta line — up to three numbers a reader looks for first, never a status or a date.

The pane-control strip a HOST supplies when it docks the view — expand and close, never record actions.

Dart for these values
screen_detail()

What it is made of

The widgets this screen assembles, with their full API below. They used to live on a second entry of their own; one thing you choose gets one page.

DetailScreen widget

The FLOORPLAN for one record (`DetailScreen.d.ts`). **Every prop here is the contract's own** since pin e04afca: syncStatus, onBack, onClose, onExpand, heroAlt, error, onRetry and loading all landed upstream, and the kit's invented `recordState` / `errorLabel` collapsed into them. Dart has no…

Full dartdoc

The FLOORPLAN for one record (`DetailScreen.d.ts`). ```dart DetailScreen<WorkOrder>( title: order.title, id: order.id, status: order.status, statusTone: toneOf(order.status), // the app's word → tone mapping meta: const [AppDetailMetaPart('Opened Sep 21 by Mo Vance')], record: order, emptyLabel: 'Record not found', sections: sections, primaryAction: DetailScreenAction( label: 'Edit', onPress: () => edit(order), ), syncStatus: SyncStatusButton(state: state, onSyncNow: syncNow), ) ``` **Every prop here is the contract's own** since pin e04afca: syncStatus, onBack, onClose, onExpand, heroAlt, error, onRetry and loading all landed upstream, and the kit's invented `recordState` / `errorLabel` collapsed into them. Dart has no `undefined`, which is exactly what loading is for: this floorplan states loading THERE and leaves record null, and `record: null` with loading false is the EMPTY face — resolved and absent.

DetailScreendefault constructor

Knob Type Default What it does
actionStyle AppDetailActionStyle
buttons · tiles
AppDetailActionStyle.buttons How the header draws secondaryActions (`DetailScreen.d.ts` `actionStyle`, THE ACTION TILES, #1907), forwarded to AppDetailView.actionStyle unchanged. AppDetailActionStyle.buttons (the default) is THE ACTION ROW; AppDetailActionStyle.tiles draws each secondary as its glyph over its caption on its own…
band FloorplanBand? null PAGE posture: the transient message band under the bar — a save confirmation, a refusal the surface must not swallow. The page mounts the same navless body-mode AppScaffold `RecordsScreen`'s pushed posture mounts (no rail, no drawer, this screen's own bar, the band under it, the Fab in the thumb…
banner Widget? null An operational notice about the SURFACE — a stale run, a blocked intent, a record open in a degraded mode, the reason a job is blocked. One at a time. ITS PLACE is the FOOT of the record header — inside the header card, below the identity and the key figures, which are the RECORD's own (THE…
columns int? null Two SECTION columns at >=960 of this screen's own box, one below (ignored under sectionNav tabs). **Null is `'auto'` and is the DEFAULT** (2026-09-24, `DetailView.d.ts`, THE WIDE DETAIL FILLS ITS REGION); `1` is the single-column opt-out and `2` is `'auto'` with the same floor. It is forwarded to…
emptyLabel * String — The empty face's copy when the record resolved and is absent.
error FloorplanError? null The load failed: `title` is the cause, `detail` one quiet line under it. Non-null outranks every other face; null means no error. It is the RECORD's error — a related section reports its own through AppDetailSection.state.
fieldLayout AppDetailFieldLayout
stacked · inline · inlineAligned
AppDetailFieldLayout.stacked Read-only field pair layout (`DetailView.d.ts` `fieldLayout`).
fieldView bool false THE FIELD VIEW (`DetailScreen.d.ts`, #1805; OPT-IN since 2026-10-29, MAJOR). Default false: no Field view in either posture, and initialPrefs / onPrefsChanged are ignored (and reported). True draws a quiet "Field view" AppIconButton opening an AppMenu of two checkable items, "Show all fields"…
figures List<AppDetailFigure> const [] Up to THREE key figures under the record's title and meta line, in the key-figure role with their units (`DetailView.d.ts` THE KEY FIGURES; Contained, 2026-09-29, #842) — what a reader looks for first (a price, a minimum order, a flash point), never a status or a date, which the header already…
hero String? null The hero image, as the kit's stored image REFERENCE (`''` renders the framed placeholder). Mutually exclusive with mediaHeader.
heroAlt String? null The hero's accessible name — set it when the photo is identity-bearing.
hideEmpty bool false EMPTY FIELDS MAY STEP ASIDE (`DetailScreen.d.ts`, #845). True hides every EMPTY field in the field sections and says so: each section that hid any closes with "3 empty fields hidden" and a Show all fields control. A section's own AppDetailSection.hideEmpty wins over this.
id String? null The record's id, rendered as the id chip.
initialPrefs DetailViewPrefs? null THE FIELD VIEW (`DetailScreen.d.ts`, 2026-10-24, #1805): the reader's restored choices, READ ONCE AT MOUNT, and only under fieldView. A host that restores asynchronously waits for its record before mounting (the `initialColumnWidths` precedent). Null: nothing chosen.
loading bool false The canonical loading signal (THE LOAD FACES). True renders the skeleton face whatever record holds, and it is the signal that MATTERS here: Dart has no `undefined`, so this is how the contract's tri-state is spelled. Default false.
mediaHeader AppMediaHeader? null A media header band in place of the plain hero.
meta List<AppDetailMetaPart> const [] THE META LINE under the title (`DetailScreen.d.ts`, Contained, #896 — MAJOR; it was a data-font annotation beside the id row): parts joined " · " — "Opened Sep 21 by Mo Vance", "Due Sep 24", `AppDetailMetaPart('5 days overdue', danger: true)`. A VALUE slot, so a blank part renders nothing and leaves…
onBack VoidCallback? null The PAGE bar's back affordance. Null renders NONE. THE EXITS ARE DECLARED, NEVER INFERRED (`DetailScreen.d.ts`, the clause of record for `FormScreen.onClose` too).
onClose VoidCallback? null Closes a HAND-BUILT pane (the unnested pane posture only): the pane strip's ✕, and Escape from anywhere in the pane but a field, through this same callback. REQUIRED with DetailScreenPresentation.pane. IGNORED under a pane host, with a debug warning (#1639 F6, THE HOST OWNS THE PANE CHROME): every…
onExpand VoidCallback? null Escalates a HAND-BUILT pane's record to its own page (the unnested pane posture only). Ignored under a pane host, with a debug warning, exactly as onClose is: the host's own expand is the one escalation. Null renders no expand — a pane with nowhere fuller to go.
onPrefsChanged ValueChanged<DetailViewPrefs>? null THE FIELD VIEW (#1805): the whole record after the reader's pick in the Field view menu, holding only the members the reader chose. Never called at mount and never from a section's own note-row toggle; only under fieldView. Null: the choice lasts the screen.
onRetry VoidCallback? null The error face's Retry. Null renders the cause with no way out.
paneActions List<Widget> const [] EXTRA pane-header controls, beside the pane's own close and expand — the hosting pane's when nested, onClose / onExpand on a hand-built pane. Never a close or an expand itself, and never record actions. Pane presentation only.
presence Widget? null THE PRESENCE STACK (`DetailScreen.d.ts` `presence`; `Presence.d.ts` EVERY FLOORPLAN CARRIES IT AS A KNOB, steady-core #1331): the `AppPresenceStack` of the scope this record joins. The HOST builds it; the screen never joins a channel. PAGE posture: this screen's own bar's AppHeaderBar.presence,…
presentation DetailScreenPresentation
auto · pane · page
DetailScreenPresentation.auto The posture: DetailScreenPresentation.auto (the default) derives it from the tree — the pane when NESTED, the page otherwise — and DetailScreenPresentation.pane / DetailScreenPresentation.page are a hand-built host's declaration (see each value).
primaryAction DetailScreenAction? null The record's one primary action (Edit by default): the header card's slab on a page at >=960, the Fab on a page below 960, the leading outline control of the action row in a pane (THE PRIMARY ACTION's placement), each wearing its DetailScreenAction.glyph.
qualifiers List<AppDetailField<T>> const [] Up to TWO short facts that qualify the record beside its status in the identity row — a priority, a category (`DetailView.d.ts` THE HEADER BLOCK). Value-only: the label is the accessible name, and the fact is never drawn on a plate. A live operation's progress rides one whose `render` is the…
record T? null The record. Null with loading false is the EMPTY face — resolved and absent, emptyLabel.
related Widget? null Related-record content a section list cannot express — a whole nested floorplan (a posts `ThreadScreen`), rendered LAST in the related region. The typed ordinary case is relatedSections; this stays the escape hatch and is neither widened into a union nor deprecated — a union would make one slot…
relatedLayout DetailScreenRelatedLayout
split · stacked
DetailScreenRelatedLayout.split Where the related region stands on a PAGE at >=960 of this screen's own width (`DetailScreen.d.ts` THE RECORD TAKES THE ROOM, AND THE HEADER SPANS, #911). DetailScreenRelatedLayout.split (the default): the header card spans both panes, the record's sections flex and the related pane is bounded, each…
relatedSectionNav AppDetailSectionNav
tabs · jump · none
AppDetailSectionNav.none The RELATED REGION's own nav over relatedSections (`DetailScreen.d.ts`, 2026-09-20). Default AppDetailSectionNav.none — the blocks stack, which is every existing call site. THIS IS NOT sectionNav REACHING THE RELATED REGION.
relatedSections List<AppDetailSection<T>> const [] Related-record blocks the floorplan renders ITSELF — the SAME typed AppDetailSection list sections takes, so a related block's heading, its count ("Posts · 3"), its Add, its See all and its own loading/error/empty state are the floorplan's to render rather than each consumer's to re-derive…
secondaryActions List<ActionSpec> const [] Quiet secondary record actions beside the primary — never a second slab.
sectionNav AppDetailSectionNav
tabs · jump · none
AppDetailSectionNav.none Section navigation posture (`DetailView.d.ts` `sectionNav`).
sectionStyle AppDetailSectionStyle?
framed · band · plain
null How a section is titled and separated (`DetailView.d.ts` THE SECTION IS A CARD). DEFAULT BY POSTURE (Contained, 2026-09-29, #896; it was band): null resolves to AppDetailSectionStyle.framed in the PAGE posture — each section its own card on the ground — and to AppDetailSectionStyle.plain in the…
sections * List<AppDetailSection<T>> — The typed field sections, in order.
status String? null The status word — encoded once; drawn as the status mark in statusTone.
statusTone AppStatusMarkTone?
pending · active · done · blocked
null The status's AppStatusMark tone (`DetailScreen.d.ts`, Contained, 2026-09-29, #896 — SUPERSEDES the deleted `statusDanger`): AppStatusMarkTone.pending · AppStatusMarkTone.active · AppStatusMarkTone.done as the word with its square marker, AppStatusMarkTone.blocked as the filled danger tag — the one…
subtitle String? null One quiet line under the title.
syncStatus * Widget? — The sync control the PAGE posture's bar carries last inline-end. Null renders no control — the pane posture never renders one either way, because the collection's bar is the surface's bar.
title * String — The record's name, in the headline role.
titleFormatRules List<FormatRule<T>>? null THE HEADLINE MAY WEAR ITS RULE (`DetailScreen.d.ts`, #1031): the title column's FORMAT RULES, forwarded to AppDetailView.titleFormatRules unchanged with record as the row, so the holding rule's MARK draws before the HEADLINE in both postures. The PAGE posture's bar title is the same string in the…

AppDetailSections widget

A bare run of AppDetailSections — the same section anatomy AppDetailView renders, with NO record header, NO key figures and no chrome of its own. It exists for the ONE place a host has to draw sections outside the record column: a detail floorplan's RELATED REGION, which at >=960 on a page sits in…

Full dartdoc

A bare run of AppDetailSections — the same section anatomy AppDetailView renders, with NO record header, NO key figures and no chrome of its own. It exists for the ONE place a host has to draw sections outside the record column: a detail floorplan's RELATED REGION, which at >=960 on a page sits in the pane BESIDE the record rather than under it, and therefore cannot be rendered by the view that drew the record. Every related block's heading, its count ("Posts · 3"), its Add, its See all and its own loading/error/empty state come from AppDetailSection exactly as they do inside the view — which is the point: a host that re-derives that wrapper is hand-rolling section chrome, and before this widget existed every one of them did, by standing up a second whole AppDetailView purely to keep the heading. AppDetailView.columns is deliberately NOT accepted: the two-track grid splits the RECORD's sections across the reading measure, and a related region is already its own column.

AppDetailSectionsdefault constructor

Knob Type Default What it does
fieldLayout AppDetailFieldLayout
stacked · inline · inlineAligned
AppDetailFieldLayout.stacked The read-only field-pair layout, threaded to every fields grid.
hideEmpty bool false EMPTY FIELDS MAY STEP ASIDE over this run — AppDetailView.hideEmpty's twin, so a related block hides exactly as the record's own sections do.
record * T — The record the sections' typed accessors read.
sectionNav AppDetailSectionNav
tabs · jump · none
AppDetailSectionNav.none How this RUN navigates itself — AppDetailSectionNav.none (the stack, every existing call site) or AppDetailSectionNav.tabs. It is the run's OWN nav, never the host view's reaching in: a `DetailScreen` passes its `relatedSectionNav` here and its `sectionNav` to AppDetailView, so the record's field…
sectionStyle AppDetailSectionStyle
framed · band · plain
AppDetailSectionStyle.plain How a section is titled and separated (`DetailView.d.ts` `sectionStyle`) — the host's own knob, threaded so a related block reads like the record's sections beside it. Framed, each block is a card, one gutter from the next, on the host's ground.
sections * List<AppDetailSection<T>> — The sections, in order. Empty renders nothing at all.
showAll bool false THE READER'S FIELD VIEW over this run — AppDetailView.showAll's twin, so a related block shows every field exactly when the record's own sections do.
windowClass AppWindowClass?
compact · medium · expanded · large
null The window class this run insets against. Null resolves it the way AppDetailView does.

UrlOpenScope widget

Provides the UrlOpen the kit opens an external address with — a detail `link` field whose value carries an `href` and no `onNavigate` (`DetailView.d.ts` THE LINK FIELD OPENS WHAT IT SAYS, #865). OPTIONAL, unlike the capture scopes: with no scope above, the kit opens through a default `UrlOpen()`…

Full dartdoc

Provides the UrlOpen the kit opens an external address with — a detail `link` field whose value carries an `href` and no `onNavigate` (`DetailView.d.ts` THE LINK FIELD OPENS WHAT IT SAYS, #865). OPTIONAL, unlike the capture scopes: with no scope above, the kit opens through a default `UrlOpen()` (the platform's external handler, the default scheme allow-list). A host wires one to narrow or widen the allow-list for its own data, and a test wires one to inject the launcher and touch no platform channel. ```dart UrlOpenScope( urlOpen: UrlOpen(schemes: {'https'}), child: MaterialApp(...), ) ```

UrlOpenScopedefault constructor

Knob Type Default What it does
child * dynamic —
urlOpen * UrlOpen — The wrapped opener.

AppTimeline widget

A record's history, newest first as the host orders it (`Timeline.d.ts` Timeline): events rendered from segments, change entries with each field `before → after`, and day rules. A TimelineEvent that is `drillable` opens onto the changes its action wrote: the host answers onExpandedChange and passes…

Full dartdoc

A record's history, newest first as the host orders it (`Timeline.d.ts` Timeline): events rendered from segments, change entries with each field `before → after`, and day rules. A TimelineEvent that is `drillable` opens onto the changes its action wrote: the host answers onExpandedChange and passes them in. ```dart AppTimeline( items: items, expandedKeys: open, onExpandedChange: (key, expanded) => setState(() => toggle(key)), hasMore: page.nextBefore != null, onLoadMore: loadOlder, ) ```

AppTimelinedefault constructor

Knob Type Default What it does
emptyLabel String 'No history yet' The empty line.
errorLabel String 'History could not be loaded.' The error sentence.
expandedKeys Set<String> const {} Keys of the events shown open.
hasMore bool false Older items exist: the list closes with "Show older".
items * List<TimelineItem> — Newest first.
loadingMore bool false The older items are loading.
onExpandedChange void Function(String key, {required bool expanded})? null An event's disclosure was toggled.
onLoadMore VoidCallback? null Loads the older items.
onRetry VoidCallback? null Offered as Retry in the error state.
status TimelineStatus
ready · loading · error
TimelineStatus.ready Ready, loading or error.

AppDeletedRecords widget

A container's deleted rows, each with Restore (`Timeline.d.ts` DeletedRecords). Restoring is the host's ordinary create; this only asks.

AppDeletedRecordsdefault constructor

Knob Type Default What it does
emptyLabel String 'Nothing deleted' The empty line.
records * List<DeletedRecord> — The deleted records, in the order given.

Types its knobs take

These are not things you choose — they are the shapes the knobs above expect. They live under this entry rather than in the navigation for exactly that reason.

ActionSpec support

One app-agnostic action — the runtime primitive behind every action button. Pure affordance metadata plus an onInvoke callback.

Field Type Default What it does
enabled bool true Whether the action is invokable. A disabled action renders grayed out and does not fire onInvoke.
glyph KitIconRef? null The action's design-system glyph. Wins over icon when both are set — the same two-channel contract every glyph-bearing kit API carries.
icon IconData? null The action's Material glyph, for a consumer that has not moved to glyph yet.
isDestructive bool false Whether the action is destructive (delete, discard, revoke). Purely a visual treatment — hosts render the affordance in the danger color role. Any confirmation dialog is the consumer's onInvoke responsibility; the action layer stays behavior-blind.
label * String — User-visible label — also the `IconButton` tooltip, the overflow menu-item text, and the `Semantics` label.
navigates bool false THE ACTION THAT ONLY OPENS A PAGE (`ActionStrip.d.ts`, steady-core #1673): true declares that invoking it does ONE thing — it opens another screen (a pushed route, a layer) and writes nothing. The host reports the control, or the ⋯ item it folds into, as a link (`Semantics(link: true)`); paint,…
onInvoke * ActionInvokeCallback — Invoked on tap. See ActionInvokeCallback.
placement ActionPlacement ActionPlacement.secondary Where the action renders. See ActionPlacement.
shortLabel String? null The primary slab's SHORT-VERB face (refinements D4: "New", never "New Observation" — the noun is the screen title). Read only where the action renders as the header-band slab; label stays the descriptive accessible name everywhere else (the compact FAB's tooltip, overflow rows). Null falls back to…
visible bool Function(BuildContext context)? null Optional visibility predicate. `null` (the default) means always visible. When non-null, hosts re-evaluate the predicate on every build and omit the affordance entirely when it returns false — independent of enabled (which grays but does not hide). Receives BuildContext so predicates can read theme,…

AppDetailField support

One typed field in an AppDetailSectionKind.fields section — a definition-list entry over the record type T. A field is pure typed metadata: a label (the definition term, on the label rail), a type deciding the value grammar (shared with the table — an ID chip, a data-font number, a status word…),…

Field Type Default What it does
danger bool Function(T record)? null Per-record danger predicate — when it returns true the value paints DesignTokens.danger AND takes em weight, in **every** grammar (an overdue date, a blocked status, a negative balance), not only on enums. Danger only where action is demanded; null never paints the value danger.
emptyLabel String? null The word rendered in place of the em-dash when this field's value is empty ('Unassigned', 'No date'). Null (the default) renders the em-dash mark. Either way the field renders — an empty value never disappears unless its section hides empty fields (AppDetailSection.hideEmpty).
formatRules List<FormatRule<T>>? null FORMAT RULES (`DetailView.d.ts` `DetailField.formatRules`, `FormatRules.d.ts`, #977) — the SAME list the record's table column declares (`AppColumn.formatRules`), so one value reads one way in a row and in a detail. The field's value is the subject; `of` reads the record the view shows. Reaches the…
formatRulesOf FormatRulesOf<Object?>? null THROUGH A REFERENCE (`DetailView.d.ts` `DetailField.formatRulesOf`, `FormatRules.d.ts`, #1032): a field that shows a reference wears the REFERENCED row's rules. `resolve` is handed the field's value and the record the view shows, and the target row is the rules' row. Walked after formatRules, only…
label * String — The definition term — rendered on the label rail in DesignTokens.label (micro-label), the `<dt>` of the definition list.
locationLabel String? Function(T record)? null AppCellType.latLong only: the place the host resolved for this record's point ("North gate, Pad 4"), drawn beside the pin IN PLACE OF the coordinates (`DetailView.d.ts` A LOCATION READS AS A PLACE, #929). The coordinates stay the tooltip and join the accessible name, and the copy button still copies…
locationPreview bool false AppCellType.latLong only: draw a still map of the point UNDER the readout (`DetailView.d.ts` A LOCATION FIELD MAY SHOW ITS MAP, #1281) — the point centered at the map's one-pin zoom with one pin, on the ambient MapTileScope's satellite raster, else the graticule plate. It is for a detail that reads…
measure AppDetailMeasure? null How this field's value wraps (`DetailView.d.ts` LONG TEXT FILLS ITS BOX, #909). Null takes the section's AppDetailSection.measure, else AppDetailMeasure.fill — the value wraps at its field box and keeps its own line breaks. AppDetailMeasure.reading caps it at 65ch of the body role, never wider than…
numberFormat AppNumberFormat? null How an AppCellType.number or AppCellType.percent value reads — `DataTable.d.ts` NumberFormat, UNCHANGED and through the table's own formatter (appCellContent), because a value does not change meaning by moving from a row to a detail. Declare the same format the column showing this datum declares.…
onEdit VoidCallback? null Per-field quick-edit callback. When set the row shows a trailing quiet edit affordance (a ghost pencil AppIconButton) and firing it invokes this. Null (the default) renders a read-only row with no affordance.
onNavigate void Function(T record)? null Navigation handler for an AppCellType.link field — the value renders accent-painted with a trailing chevron on a ≥DesignTokens.touch target, and firing it invokes this with the record. Null renders the inert link form (the reference still SHOWS; it just does not pretend to navigate). Unlike onEdit…
options List<FieldOption>? null AN OPTION'S LABEL READS IN THE DETAIL (`DetailView.d.ts` `DetailField.options`, 2026-10-20, #1635): the SAME list the field's form editor and its table column take (`AppColumn.options`), so one datum prints one string on the form, the cell and the detail. Read by AppCellType.enumValue,…
refLabel String? Function(String id)? null AppCellType.ref / AppCellType.refList: a stored key's label (`DetailView.d.ts` `DetailField.refLabel`, EVERY FORM TYPE HAS A READ FACE, #1645) — the same resolver the field's form editor and its table column read (`AppColumn.refLabel`). A null or blank answer leaves the key UNRESOLVED: the key…
render Widget Function(T record)? null Full custom value builder — the escape hatch mirroring `AppColumn.render`. When non-null it wins over type, emptyLabel and the empty mark entirely: the caller owns the whole value widget. Use sparingly; the canonical grammars (type) cover the common cases, and a bespoke value in a definition list is…
span int 1 Column span in the field grid — 1 (the default), 2 (two tracks), or spanFull (the whole row at every track count). Clamped to the live track count, so a span never overflows the grid; ignored by the inline layouts, whose value already fills the row.
status AppStatusMarkTone? Function(T record)? null STATUS (`DetailView.d.ts` `DetailField.status`, Contained, 2026-09-29, #893) — the value is a stored status, rendered as the STATUS MARK (AppStatusMark) in the tone this returns for the record: the word with its marker, or the filled danger tag for AppStatusMarkTone.blocked. It WINS over danger —…
tier AppDetailFieldTier AppDetailFieldTier.primary A FIELD MAY STEP ASIDE BY ITS TIER (`DetailView.d.ts` `DetailField.tier`, 2026-10-24, #1805). AppDetailFieldTier.primary (the default) renders as before; AppDetailFieldTier.secondary is hidden behind its section's note row until the reader shows it, then in its authored place. It needs no…
type AppCellType AppCellType.text How the value renders — the shared AppCellType grammar. Defaults to AppCellType.text. Ignored when render is supplied.
unitOf AppNumberUnit? Function(T record)? null THE ROW'S OWN UNIT (`DetailView.d.ts` `DetailField.unitOf`, #884) — the same accessor the record's column declares (`AppColumn.unitOf`), read against the record the view shows. A present result replaces numberFormat's unit; null or blank leaves it standing; with no numberFormat the unit trails the…
units List<QuantityUnit>? null AppCellType.quantity: the unit choices (`FieldSpec.units`, `DetailView.d.ts` `DetailField.units`, #1645), read for each code's label (`150 psig`). Ignored by every other type. Null: a unit reads as its code.
value * Object? Function(T record) — Typed value accessor — reads this field's value from a record. Its return type pairs with type (a `String` for id/text/enumValue/person, a `num` for number/progress, a `String`/`DateTime` for date, an `ImageProvider?` for image). A closure over the typed record — never a map lookup.

AppDetailFigure support

One KEY FIGURE (`DetailView.d.ts` THE KEY FIGURES, Contained, 2026-09-29, #842) — a number a reader looks for first (a price, a minimum order, a flash point, how overdue a job is), never a status or a date: the status belongs to the identity row and dates to the meta line. It SUPERSEDES the deleted…

Field Type Default What it does
danger bool false Paints the figure (never its label) DesignTokens.danger — only where someone has to act ("Overdue 5 days").
label * String — The label role over the figure ("Flash point") — sentence case. It ellipses; the figure never does.
numberFormat AppNumberFormat? null `DataTable.d.ts` NumberFormat, through the table's formatter.
value * num? —
Field Type Default What it does
danger bool false Paints the figure (never its label) DesignTokens.danger — only where someone has to act ("Overdue 5 days").
label * String — The label role over the figure ("Flash point") — sentence case. It ellipses; the figure never does.
numberFormat AppNumberFormat? null `DataTable.d.ts` NumberFormat, through the table's formatter.
value * num? —
Field Type Default What it does
danger bool false Paints the figure (never its label) DesignTokens.danger — only where someone has to act ("Overdue 5 days").
label * String — The label role over the figure ("Flash point") — sentence case. It ellipses; the figure never does.
value * String? —

AppDetailMetaPart support

One part of THE META LINE (`DetailView.d.ts` THE HEADER BLOCK, #896) — plain text, or a run that demands action ("5 days overdue", danger) drawn in DesignTokens.danger at the em weight. A blank part renders nothing and takes no separator (a VALUE slot, `List.d.ts`).

Field Type Default What it does
text * String — The part's words — "Opened Sep 21 by Mo Vance", "Due Sep 24".
danger bool false Paints the part danger at the em weight — the one color the header's prose takes, and only where someone has to act.

AppDetailSection support

One section of an AppDetailView — a labeled block of one AppDetailSectionKind. Generic over the record type T so its typed content (fields, custom builder) reads the record without a map.

Field Type Default What it does
addNavigates bool false THE ACTION THAT ONLY OPENS A PAGE (`ActionStrip.d.ts`, #1744): onAdd pushes the record form and writes nothing, so every Add this section draws (the heading's, the empty face's, a records footer's) reports a link to assistive technology. Declared, never inferred from onAdd. It does not apply while…
collapsed bool? null The CONTROLLED collapse state of a collapsible section (`DetailView.d.ts` A SECTION'S COLLAPSE MAY BE CONTROLLED, #1029). Set, it is the section's state on every build: the head's toggle (a tap, Enter or Space) only reports the state it asks for through onCollapsedChanged and changes nothing itself,…
collapsible bool false When true, the section header carries a disclosure toggle and the body collapses/expands — the view's state, seeded by initiallyCollapsed, or the host's when it sets collapsed.
count int? null Related-section item count — rendered as a data-font count trailing the heading label, and (with onSeeAll) folded into "See all ($count)". A count of 0 renders the designed empty state (emptyLabel/emptyBuilder) in place of the body. Null renders no count and no count-driven empty gate.
emptyBody String? null One quiet factual line under the empty face's title (`DetailSection.emptyBody`). Null renders no second line. Ignored when emptyBuilder is supplied — that builder owns the whole face.
emptyBuilder WidgetBuilder? null A custom empty-state builder — takes precedence over emptyLabel when the section is empty, letting the caller build a richer empty composition. Fields/custom kinds only.
emptyLabel String? null The one-line empty-state copy ("No related records yet"). When set and the section is empty (count `== 0`, or emptyBuilder/emptyLabel with an empty fields list), a designed empty composition (a glyph + this label) renders in place of the body. Fields/custom kinds only.
errorLabel String? null The one-line failure copy for AppDetailSectionState.error ("Related records could not load."). Null falls back to a generic factual line — never an apology, never the empty label.
fields * List<AppDetailField<T>>? — The typed fields for an AppDetailSectionKind.fields section; null for every other kind.
headAction Widget? null A trailing control slot on the section header band (`DetailSection. headAction` — e.g. an "Add item" ghost button), rendered trailing-most, outside the collapse toggle's tap target. A SLOT, not a knob: the caller owns the widget; null renders nothing. For the canonical add / see-all affordances…
hideEmpty bool? null Hides this section's EMPTY fields behind the note row ("3 empty fields hidden" · Show all fields) — `fields` and grouped sections only (`DetailView.d.ts` EMPTY FIELDS MAY STEP ASIDE, #845). Null takes the view's AppDetailView.hideEmpty; set, it wins over the view's. Hiding never changes count.
initiallyCollapsed bool false Initial collapse state for a collapsible section (the `initial*` idiom — the view owns the state thereafter). Read once, when the view first sees the section, and never re-seeded by a later value. Ignored when collapsible is false, and while collapsed is set.
label * String — The section heading — rendered in the TITLE role (DesignTokens.title, full DesignTokens.ink) in the caller's own case ("Overview", not "OVERVIEW"), and exposed as a semantic heading. The micro-label is reserved for FIELD labels.
measure AppDetailMeasure? null How this section's long values wrap — its fields, its groups' fields and its text (`DetailView.d.ts` LONG TEXT FILLS ITS BOX, #909). A field's own AppDetailField.measure wins. Null is AppDetailMeasure.fill.
meta String? null A quiet data-font annotation on the heading ("2 of 5", "3 photos") — right of the label. Null renders no meta. Distinct from count: meta is free annotation text, count is the related-list item count (drives the "See all ($count)" label + the empty-state gate).
onAdd VoidCallback? null Related-section create verb. ADD IS ALWAYS LABELED (`DetailView.d.ts`, 2026-09-29, #857): a ghost AppButton carrying the plus glyph AND the word "Add", trailing on the heading band, named "Add recordNoun" for assistive tech when the noun is set — never an icon-only `+`, which hid the create path.…
onCollapsedChanged ValueChanged<bool>? null Reports the state a reader's toggle asks for — `true` to collapse — controlled or not, so a host may OBSERVE an uncontrolled section without controlling it (`DetailView.d.ts` A SECTION'S COLLAPSE MAY BE CONTROLLED, #1029; React `DetailSection.onCollapsedChange`). Fires for the user's own toggle…
onRetry VoidCallback? null The error state's single way out — rendered as one quiet "Retry" action under errorLabel. Null renders the failure statement alone (a host with no retry channel still states the fact).
onSeeAll VoidCallback? null Related-section "See all" affordance — a quiet trailing text button in the heading ("See all", or "See all ($count)" when count is non-null), firing this. Null renders no see-all. Fields/custom kinds only.
placement AppDetailSectionPlacement AppDetailSectionPlacement.main Where this section stands when the body has two columns (`DetailView.d.ts` THE SIDE TRACK, #896). Default AppDetailSectionPlacement.main; AppDetailSectionPlacement.side stands it in the 372 side track beside the main one — the record's CONTEXT (its location, its activity), not its own facts. Below…
recordNoun String? null The singular noun one related row names ("line item"), sentence case, no article (`DetailSection.recordNoun`). It completes the create verb — "Add line item" on the empty face — and names the heading Add for a screen reader. Null reads every Add as "Add".
span AppDetailSectionSpan? null This section's width in the equal two-up body (`DetailView.d.ts` THE SECTION SPANS, #924): AppDetailSectionSpan.full takes both tracks and AppDetailSectionSpan.track one. Null takes the kind's default — full for a records section (a table of child rows is wider than it is tall, and a half track…
state AppDetailSectionState AppDetailSectionState.ready Whether this section's content is resolved, still loading, or failed. Defaults to AppDetailSectionState.ready — a section constructed with no state knob renders exactly as it always did. Fields/custom kinds only.
Field Type Default What it does
addNavigates bool false THE ACTION THAT ONLY OPENS A PAGE (`ActionStrip.d.ts`, #1744): onAdd pushes the record form and writes nothing, so every Add this section draws (the heading's, the empty face's, a records footer's) reports a link to assistive technology. Declared, never inferred from onAdd. It does not apply while…
collapsed bool? null The CONTROLLED collapse state of a collapsible section (`DetailView.d.ts` A SECTION'S COLLAPSE MAY BE CONTROLLED, #1029). Set, it is the section's state on every build: the head's toggle (a tap, Enter or Space) only reports the state it asks for through onCollapsedChanged and changes nothing itself,…
collapsible bool false When true, the section header carries a disclosure toggle and the body collapses/expands — the view's state, seeded by initiallyCollapsed, or the host's when it sets collapsed.
count int? null Related-section item count — rendered as a data-font count trailing the heading label, and (with onSeeAll) folded into "See all ($count)". A count of 0 renders the designed empty state (emptyLabel/emptyBuilder) in place of the body. Null renders no count and no count-driven empty gate.
custom * Widget Function(T record)? — The body builder for a AppDetailSectionKind.custom section; null for every other kind.
emptyBody String? null One quiet factual line under the empty face's title (`DetailSection.emptyBody`). Null renders no second line. Ignored when emptyBuilder is supplied — that builder owns the whole face.
emptyBuilder WidgetBuilder? null A custom empty-state builder — takes precedence over emptyLabel when the section is empty, letting the caller build a richer empty composition. Fields/custom kinds only.
emptyLabel String? null The one-line empty-state copy ("No related records yet"). When set and the section is empty (count `== 0`, or emptyBuilder/emptyLabel with an empty fields list), a designed empty composition (a glyph + this label) renders in place of the body. Fields/custom kinds only.
errorLabel String? null The one-line failure copy for AppDetailSectionState.error ("Related records could not load."). Null falls back to a generic factual line — never an apology, never the empty label.
headAction Widget? null A trailing control slot on the section header band (`DetailSection. headAction` — e.g. an "Add item" ghost button), rendered trailing-most, outside the collapse toggle's tap target. A SLOT, not a knob: the caller owns the widget; null renders nothing. For the canonical add / see-all affordances…
initiallyCollapsed bool false Initial collapse state for a collapsible section (the `initial*` idiom — the view owns the state thereafter). Read once, when the view first sees the section, and never re-seeded by a later value. Ignored when collapsible is false, and while collapsed is set.
label * String — The section heading — rendered in the TITLE role (DesignTokens.title, full DesignTokens.ink) in the caller's own case ("Overview", not "OVERVIEW"), and exposed as a semantic heading. The micro-label is reserved for FIELD labels.
meta String? null A quiet data-font annotation on the heading ("2 of 5", "3 photos") — right of the label. Null renders no meta. Distinct from count: meta is free annotation text, count is the related-list item count (drives the "See all ($count)" label + the empty-state gate).
onAdd VoidCallback? null Related-section create verb. ADD IS ALWAYS LABELED (`DetailView.d.ts`, 2026-09-29, #857): a ghost AppButton carrying the plus glyph AND the word "Add", trailing on the heading band, named "Add recordNoun" for assistive tech when the noun is set — never an icon-only `+`, which hid the create path.…
onCollapsedChanged ValueChanged<bool>? null Reports the state a reader's toggle asks for — `true` to collapse — controlled or not, so a host may OBSERVE an uncontrolled section without controlling it (`DetailView.d.ts` A SECTION'S COLLAPSE MAY BE CONTROLLED, #1029; React `DetailSection.onCollapsedChange`). Fires for the user's own toggle…
onRetry VoidCallback? null The error state's single way out — rendered as one quiet "Retry" action under errorLabel. Null renders the failure statement alone (a host with no retry channel still states the fact).
onSeeAll VoidCallback? null Related-section "See all" affordance — a quiet trailing text button in the heading ("See all", or "See all ($count)" when count is non-null), firing this. Null renders no see-all. Fields/custom kinds only.
placement AppDetailSectionPlacement AppDetailSectionPlacement.main Where this section stands when the body has two columns (`DetailView.d.ts` THE SIDE TRACK, #896). Default AppDetailSectionPlacement.main; AppDetailSectionPlacement.side stands it in the 372 side track beside the main one — the record's CONTEXT (its location, its activity), not its own facts. Below…
recordNoun String? null The singular noun one related row names ("line item"), sentence case, no article (`DetailSection.recordNoun`). It completes the create verb — "Add line item" on the empty face — and names the heading Add for a screen reader. Null reads every Add as "Add".
span AppDetailSectionSpan? null This section's width in the equal two-up body (`DetailView.d.ts` THE SECTION SPANS, #924): AppDetailSectionSpan.full takes both tracks and AppDetailSectionSpan.track one. Null takes the kind's default — full for a records section (a table of child rows is wider than it is tall, and a half track…
state AppDetailSectionState AppDetailSectionState.ready Whether this section's content is resolved, still loading, or failed. Defaults to AppDetailSectionState.ready — a section constructed with no state knob renders exactly as it always did. Fields/custom kinds only.
Field Type Default What it does
collapsed bool? null The CONTROLLED collapse state of a collapsible section (`DetailView.d.ts` A SECTION'S COLLAPSE MAY BE CONTROLLED, #1029). Set, it is the section's state on every build: the head's toggle (a tap, Enter or Space) only reports the state it asks for through onCollapsedChanged and changes nothing itself,…
collapsible bool false When true, the section header carries a disclosure toggle and the body collapses/expands — the view's state, seeded by initiallyCollapsed, or the host's when it sets collapsed.
groups * List<AppDetailFieldGroup<T>>? — The labeled field runs for an AppDetailSectionKind.groups section; null for every other kind. Mutually exclusive with fields — a section is one or the other.
headAction Widget? null A trailing control slot on the section header band (`DetailSection. headAction` — e.g. an "Add item" ghost button), rendered trailing-most, outside the collapse toggle's tap target. A SLOT, not a knob: the caller owns the widget; null renders nothing. For the canonical add / see-all affordances…
hideEmpty bool? null Hides this section's EMPTY fields behind the note row ("3 empty fields hidden" · Show all fields) — `fields` and grouped sections only (`DetailView.d.ts` EMPTY FIELDS MAY STEP ASIDE, #845). Null takes the view's AppDetailView.hideEmpty; set, it wins over the view's. Hiding never changes count.
initiallyCollapsed bool false Initial collapse state for a collapsible section (the `initial*` idiom — the view owns the state thereafter). Read once, when the view first sees the section, and never re-seeded by a later value. Ignored when collapsible is false, and while collapsed is set.
label * String — The section heading — rendered in the TITLE role (DesignTokens.title, full DesignTokens.ink) in the caller's own case ("Overview", not "OVERVIEW"), and exposed as a semantic heading. The micro-label is reserved for FIELD labels.
measure AppDetailMeasure? null How this section's long values wrap — its fields, its groups' fields and its text (`DetailView.d.ts` LONG TEXT FILLS ITS BOX, #909). A field's own AppDetailField.measure wins. Null is AppDetailMeasure.fill.
meta String? null A quiet data-font annotation on the heading ("2 of 5", "3 photos") — right of the label. Null renders no meta. Distinct from count: meta is free annotation text, count is the related-list item count (drives the "See all ($count)" label + the empty-state gate).
onCollapsedChanged ValueChanged<bool>? null Reports the state a reader's toggle asks for — `true` to collapse — controlled or not, so a host may OBSERVE an uncontrolled section without controlling it (`DetailView.d.ts` A SECTION'S COLLAPSE MAY BE CONTROLLED, #1029; React `DetailSection.onCollapsedChange`). Fires for the user's own toggle…
placement AppDetailSectionPlacement AppDetailSectionPlacement.main Where this section stands when the body has two columns (`DetailView.d.ts` THE SIDE TRACK, #896). Default AppDetailSectionPlacement.main; AppDetailSectionPlacement.side stands it in the 372 side track beside the main one — the record's CONTEXT (its location, its activity), not its own facts. Below…
span AppDetailSectionSpan? null This section's width in the equal two-up body (`DetailView.d.ts` THE SECTION SPANS, #924): AppDetailSectionSpan.full takes both tracks and AppDetailSectionSpan.track one. Null takes the kind's default — full for a records section (a table of child rows is wider than it is tall, and a half track…
Field Type Default What it does
collapsed bool? null The CONTROLLED collapse state of a collapsible section (`DetailView.d.ts` A SECTION'S COLLAPSE MAY BE CONTROLLED, #1029). Set, it is the section's state on every build: the head's toggle (a tap, Enter or Space) only reports the state it asks for through onCollapsedChanged and changes nothing itself,…
collapsible bool false When true, the section header carries a disclosure toggle and the body collapses/expands — the view's state, seeded by initiallyCollapsed, or the host's when it sets collapsed.
emptyLabel String? null The one-line empty-state copy ("No related records yet"). When set and the section is empty (count `== 0`, or emptyBuilder/emptyLabel with an empty fields list), a designed empty composition (a glyph + this label) renders in place of the body. Fields/custom kinds only.
headAction Widget? null A trailing control slot on the section header band (`DetailSection. headAction` — e.g. an "Add item" ghost button), rendered trailing-most, outside the collapse toggle's tap target. A SLOT, not a knob: the caller owns the widget; null renders nothing. For the canonical add / see-all affordances…
initiallyCollapsed bool false Initial collapse state for a collapsible section (the `initial*` idiom — the view owns the state thereafter). Read once, when the view first sees the section, and never re-seeded by a later value. Ignored when collapsible is false, and while collapsed is set.
label * String — The section heading — rendered in the TITLE role (DesignTokens.title, full DesignTokens.ink) in the caller's own case ("Overview", not "OVERVIEW"), and exposed as a semantic heading. The micro-label is reserved for FIELD labels.
location * AppDetailLocation<T>? — THE LOCATION PREVIEW's content for an AppDetailSectionKind.location section (#930); null for every other kind.
meta String? null A quiet data-font annotation on the heading ("2 of 5", "3 photos") — right of the label. Null renders no meta. Distinct from count: meta is free annotation text, count is the related-list item count (drives the "See all ($count)" label + the empty-state gate).
onCollapsedChanged ValueChanged<bool>? null Reports the state a reader's toggle asks for — `true` to collapse — controlled or not, so a host may OBSERVE an uncontrolled section without controlling it (`DetailView.d.ts` A SECTION'S COLLAPSE MAY BE CONTROLLED, #1029; React `DetailSection.onCollapsedChange`). Fires for the user's own toggle…
placement AppDetailSectionPlacement AppDetailSectionPlacement.main Where this section stands when the body has two columns (`DetailView.d.ts` THE SIDE TRACK, #896). Default AppDetailSectionPlacement.main; AppDetailSectionPlacement.side stands it in the 372 side track beside the main one — the record's CONTEXT (its location, its activity), not its own facts. Below…
span AppDetailSectionSpan? null This section's width in the equal two-up body (`DetailView.d.ts` THE SECTION SPANS, #924): AppDetailSectionSpan.full takes both tracks and AppDetailSectionSpan.track one. Null takes the kind's default — full for a records section (a table of child rows is wider than it is tall, and a half track…
Field Type Default What it does
collapsed bool? null The CONTROLLED collapse state of a collapsible section (`DetailView.d.ts` A SECTION'S COLLAPSE MAY BE CONTROLLED, #1029). Set, it is the section's state on every build: the head's toggle (a tap, Enter or Space) only reports the state it asks for through onCollapsedChanged and changes nothing itself,…
collapsible bool false When true, the section header carries a disclosure toggle and the body collapses/expands — the view's state, seeded by initiallyCollapsed, or the host's when it sets collapsed.
headAction Widget? null A trailing control slot on the section header band (`DetailSection. headAction` — e.g. an "Add item" ghost button), rendered trailing-most, outside the collapse toggle's tap target. A SLOT, not a knob: the caller owns the widget; null renders nothing. For the canonical add / see-all affordances…
initiallyCollapsed bool false Initial collapse state for a collapsible section (the `initial*` idiom — the view owns the state thereafter). Read once, when the view first sees the section, and never re-seeded by a later value. Ignored when collapsible is false, and while collapsed is set.
label * String — The section heading — rendered in the TITLE role (DesignTokens.title, full DesignTokens.ink) in the caller's own case ("Overview", not "OVERVIEW"), and exposed as a semantic heading. The micro-label is reserved for FIELD labels.
media * List<AppDetailMediaItem>? — The media items for a AppDetailSectionKind.media section; null for every other kind.
meta String? null A quiet data-font annotation on the heading ("2 of 5", "3 photos") — right of the label. Null renders no meta. Distinct from count: meta is free annotation text, count is the related-list item count (drives the "See all ($count)" label + the empty-state gate).
onCollapsedChanged ValueChanged<bool>? null Reports the state a reader's toggle asks for — `true` to collapse — controlled or not, so a host may OBSERVE an uncontrolled section without controlling it (`DetailView.d.ts` A SECTION'S COLLAPSE MAY BE CONTROLLED, #1029; React `DetailSection.onCollapsedChange`). Fires for the user's own toggle…
placement AppDetailSectionPlacement AppDetailSectionPlacement.main Where this section stands when the body has two columns (`DetailView.d.ts` THE SIDE TRACK, #896). Default AppDetailSectionPlacement.main; AppDetailSectionPlacement.side stands it in the 372 side track beside the main one — the record's CONTEXT (its location, its activity), not its own facts. Below…
span AppDetailSectionSpan? null This section's width in the equal two-up body (`DetailView.d.ts` THE SECTION SPANS, #924): AppDetailSectionSpan.full takes both tracks and AppDetailSectionSpan.track one. Null takes the kind's default — full for a records section (a table of child rows is wider than it is tall, and a half track…
Field Type Default What it does
addNavigates bool false THE ACTION THAT ONLY OPENS A PAGE (`ActionStrip.d.ts`, #1744): onAdd pushes the record form and writes nothing, so every Add this section draws (the heading's, the empty face's, a records footer's) reports a link to assistive technology. Declared, never inferred from onAdd. It does not apply while…
collapsed bool? null The CONTROLLED collapse state of a collapsible section (`DetailView.d.ts` A SECTION'S COLLAPSE MAY BE CONTROLLED, #1029). Set, it is the section's state on every build: the head's toggle (a tap, Enter or Space) only reports the state it asks for through onCollapsedChanged and changes nothing itself,…
collapsible bool false When true, the section header carries a disclosure toggle and the body collapses/expands — the view's state, seeded by initiallyCollapsed, or the host's when it sets collapsed.
count int? null Related-section item count — rendered as a data-font count trailing the heading label, and (with onSeeAll) folded into "See all ($count)". A count of 0 renders the designed empty state (emptyLabel/emptyBuilder) in place of the body. Null renders no count and no count-driven empty gate.
emptyBody String? null One quiet factual line under the empty face's title (`DetailSection.emptyBody`). Null renders no second line. Ignored when emptyBuilder is supplied — that builder owns the whole face.
emptyLabel String? null The one-line empty-state copy ("No related records yet"). When set and the section is empty (count `== 0`, or emptyBuilder/emptyLabel with an empty fields list), a designed empty composition (a glyph + this label) renders in place of the body. Fields/custom kinds only.
errorLabel String? null The one-line failure copy for AppDetailSectionState.error ("Related records could not load."). Null falls back to a generic factual line — never an apology, never the empty label.
headAction Widget? null A trailing control slot on the section header band (`DetailSection. headAction` — e.g. an "Add item" ghost button), rendered trailing-most, outside the collapse toggle's tap target. A SLOT, not a knob: the caller owns the widget; null renders nothing. For the canonical add / see-all affordances…
initiallyCollapsed bool false Initial collapse state for a collapsible section (the `initial*` idiom — the view owns the state thereafter). Read once, when the view first sees the section, and never re-seeded by a later value. Ignored when collapsible is false, and while collapsed is set.
label * String — The section heading — rendered in the TITLE role (DesignTokens.title, full DesignTokens.ink) in the caller's own case ("Overview", not "OVERVIEW"), and exposed as a semantic heading. The micro-label is reserved for FIELD labels.
meta String? null A quiet data-font annotation on the heading ("2 of 5", "3 photos") — right of the label. Null renders no meta. Distinct from count: meta is free annotation text, count is the related-list item count (drives the "See all ($count)" label + the empty-state gate).
onAdd VoidCallback? null Related-section create verb. ADD IS ALWAYS LABELED (`DetailView.d.ts`, 2026-09-29, #857): a ghost AppButton carrying the plus glyph AND the word "Add", trailing on the heading band, named "Add recordNoun" for assistive tech when the noun is set — never an icon-only `+`, which hid the create path.…
onCollapsedChanged ValueChanged<bool>? null Reports the state a reader's toggle asks for — `true` to collapse — controlled or not, so a host may OBSERVE an uncontrolled section without controlling it (`DetailView.d.ts` A SECTION'S COLLAPSE MAY BE CONTROLLED, #1029; React `DetailSection.onCollapsedChange`). Fires for the user's own toggle…
onRetry VoidCallback? null The error state's single way out — rendered as one quiet "Retry" action under errorLabel. Null renders the failure statement alone (a host with no retry channel still states the fact).
onSeeAll VoidCallback? null Related-section "See all" affordance — a quiet trailing text button in the heading ("See all", or "See all ($count)" when count is non-null), firing this. Null renders no see-all. Fields/custom kinds only.
placement AppDetailSectionPlacement AppDetailSectionPlacement.main Where this section stands when the body has two columns (`DetailView.d.ts` THE SIDE TRACK, #896). Default AppDetailSectionPlacement.main; AppDetailSectionPlacement.side stands it in the 372 side track beside the main one — the record's CONTEXT (its location, its activity), not its own facts. Below…
recordNoun String? null The singular noun one related row names ("line item"), sentence case, no article (`DetailSection.recordNoun`). It completes the create verb — "Add line item" on the empty face — and names the heading Add for a screen reader. Null reads every Add as "Add".
records * AppDetailRecords<Object?> —
span AppDetailSectionSpan? null This section's width in the equal two-up body (`DetailView.d.ts` THE SECTION SPANS, #924): AppDetailSectionSpan.full takes both tracks and AppDetailSectionSpan.track one. Null takes the kind's default — full for a records section (a table of child rows is wider than it is tall, and a half track…
state AppDetailSectionState AppDetailSectionState.ready Whether this section's content is resolved, still loading, or failed. Defaults to AppDetailSectionState.ready — a section constructed with no state knob renders exactly as it always did. Fields/custom kinds only.
Field Type Default What it does
panels * List<AppDetailSlotPanel> —
placement AppDetailSectionPlacement AppDetailSectionPlacement.main Where this section stands when the body has two columns (`DetailView.d.ts` THE SIDE TRACK, #896). Default AppDetailSectionPlacement.main; AppDetailSectionPlacement.side stands it in the 372 side track beside the main one — the record's CONTEXT (its location, its activity), not its own facts. Below…
slot * String —
span AppDetailSectionSpan? null This section's width in the equal two-up body (`DetailView.d.ts` THE SECTION SPANS, #924): AppDetailSectionSpan.full takes both tracks and AppDetailSectionSpan.track one. Null takes the kind's default — full for a records section (a table of child rows is wider than it is tall, and a half track…
Field Type Default What it does
collapsed bool? null The CONTROLLED collapse state of a collapsible section (`DetailView.d.ts` A SECTION'S COLLAPSE MAY BE CONTROLLED, #1029). Set, it is the section's state on every build: the head's toggle (a tap, Enter or Space) only reports the state it asks for through onCollapsedChanged and changes nothing itself,…
collapsible bool false When true, the section header carries a disclosure toggle and the body collapses/expands — the view's state, seeded by initiallyCollapsed, or the host's when it sets collapsed.
headAction Widget? null A trailing control slot on the section header band (`DetailSection. headAction` — e.g. an "Add item" ghost button), rendered trailing-most, outside the collapse toggle's tap target. A SLOT, not a knob: the caller owns the widget; null renders nothing. For the canonical add / see-all affordances…
initiallyCollapsed bool false Initial collapse state for a collapsible section (the `initial*` idiom — the view owns the state thereafter). Read once, when the view first sees the section, and never re-seeded by a later value. Ignored when collapsible is false, and while collapsed is set.
label * String — The section heading — rendered in the TITLE role (DesignTokens.title, full DesignTokens.ink) in the caller's own case ("Overview", not "OVERVIEW"), and exposed as a semantic heading. The micro-label is reserved for FIELD labels.
measure AppDetailMeasure? null How this section's long values wrap — its fields, its groups' fields and its text (`DetailView.d.ts` LONG TEXT FILLS ITS BOX, #909). A field's own AppDetailField.measure wins. Null is AppDetailMeasure.fill.
meta String? null A quiet data-font annotation on the heading ("2 of 5", "3 photos") — right of the label. Null renders no meta. Distinct from count: meta is free annotation text, count is the related-list item count (drives the "See all ($count)" label + the empty-state gate).
onCollapsedChanged ValueChanged<bool>? null Reports the state a reader's toggle asks for — `true` to collapse — controlled or not, so a host may OBSERVE an uncontrolled section without controlling it (`DetailView.d.ts` A SECTION'S COLLAPSE MAY BE CONTROLLED, #1029; React `DetailSection.onCollapsedChange`). Fires for the user's own toggle…
placement AppDetailSectionPlacement AppDetailSectionPlacement.main Where this section stands when the body has two columns (`DetailView.d.ts` THE SIDE TRACK, #896). Default AppDetailSectionPlacement.main; AppDetailSectionPlacement.side stands it in the 372 side track beside the main one — the record's CONTEXT (its location, its activity), not its own facts. Below…
span AppDetailSectionSpan? null This section's width in the equal two-up body (`DetailView.d.ts` THE SECTION SPANS, #924): AppDetailSectionSpan.full takes both tracks and AppDetailSectionSpan.track one. Null takes the kind's default — full for a records section (a table of child rows is wider than it is tall, and a half track…
text * String? — The prose for a AppDetailSectionKind.text section; null for every other kind.

DeletedRecord support

One deleted record (`Timeline.d.ts` DeletedRecord).

Field Type Default What it does
at * String — When, as the host words it.
deletedBy * String? — Who deleted it; null renders "Someone". Never an e-mail.
key * String — Stable and unique in the list.
onRestore VoidCallback? null Offered when given: re-create the record.
restoring bool false The restore is in flight.
title * String — The record's label.

DetailScreenAction support

The record's one primary action. The header card's slab on a page at >=960, the Fab on a page below it, the leading outline control in a pane — each wearing glyph (`DetailScreen.d.ts` THE PRIMARY WEARS ITS OWN GLYPH).

Field Type Default What it does
glyph KitIconRef KitGlyph.edit The action's mark in all three placements (the contract's `icon`).
label * String — The verb — the slab's and the pane control's label, and the Fab's tooltip and accessible name.
navigates bool false THE ACTION THAT ONLY OPENS A PAGE (`ActionStrip.d.ts`, #1744): pressing it pushes another screen and writes nothing. Every placement (the slab, the Fab, the pane control) then reports a link to assistive technology. Declared, never inferred from onPress; leave it false for an action that writes and…
onPress * VoidCallback — Invoked from every placement.

DetailViewPrefs support

THE FIELD VIEW's record (`DetailScreen.d.ts` `DetailViewPrefs`, #1805): the reader's two choices about which fields a record shows, and what `DetailScreen.onPrefsChanged` reports. **It holds only what the reader CHOSE**, in the `RecordsViewPrefs` grammar (RecordsScreen.d.ts THE VIEW RECORD HOLDS…

Field Type Default What it does
hideEmpty bool? null Empty fields hidden, or null for never chosen. It wins over the screen's `hideEmpty` knob, never over a section's own `AppDetailSection.hideEmpty`: a section that must show its blanks (a checklist) says so itself.
showAll bool? null Every field shown, secondary and empty alike (`AppDetailView.showAll`), or null for never chosen (every section then hides what it would).
Field Type Default What it does
json * Map<String, Object?> —

FloorplanBand support

A floorplan's ONE TRANSIENT BAND — the contract's `ScaffoldHeaderBandProps` on both floorplans that declare one, stated once here rather than twice. `DetailScreen.d.ts` and `RecordsScreen.d.ts` each type their `band` member as that shared props type and forward it VERBATIM, so a Dart type per…

Field Type Default What it does
actionLabel String? null Label for the ONE action beside message (the Undo pattern).
message String? null The transient message. Null draws nothing.
onAction VoidCallback? null Callback for that single action.

FormatRule support

One FORMAT RULE (`FormatRules.d.ts` THE FORMAT RULE): a match and its effects. A rule list is ORDERED and the FIRST holding rule formats the value; a rule with no match always holds, so written last it is the column's default.

Field Type Default What it does
color KitColor? null A palette name or a color parsed from data — on a map pin, its FILL.
em bool false The word at the em weight.
glyph KitIconRef? null A glyph — on a map pin, the head's glyph.
italic bool false The word italic.
label String? null What the rule means, in the host's words — read by a legend, a chip and the accessible name.
match FormatMatch<T>? null The predicate, or null for "always holds" (the default rule).
muted bool false The word at ink40 (ignored under FormatPaint.ink and FormatPaint.tag).
paint FormatPaint FormatPaint.mark How color lands on a value (FormatPaint.mark by default).
strike bool false The word struck through, in its own ink.

TimelineItem support

One item of a AppTimeline: an event, a change, or a day rule.

Field Type Default What it does
key * String — Stable and unique in the list: the item's identity.

Where it lives

Class File
DetailScreen packages/app_widgets/lib/src/floorplans/detail_screen.dart
AppDetailSections packages/app_widgets/lib/src/kit/data/detail_view.dart
UrlOpenScope packages/app_widgets/lib/src/sync_scope/url_open_scope.dart
AppTimeline packages/app_widgets/lib/src/kit/data/timeline.dart
AppDeletedRecords packages/app_widgets/lib/src/kit/data/timeline.dart