Skip to content

13 - Section Anatomy

The inside of a template. 03-layout.md says what archetype a page is. 11-templates-catalog.md says which template within the archetype. This file says what’s inside the template — the named areas, the required elements per area, and the canonical row patterns for presenting different kinds of information within a section.

Scope rule. When a behavior is already covered in 04-components.md (per-primitive rules), 05-patterns.md (cross-cutting UI patterns), or 03-layout.md (page-level layout), this file points there. New anatomy lives only for the within-template structure.

Prereqs: 03-layout.md, 04-components.md, 11-templates-catalog.md.


How to read this doc

  • Area = a named region within a template (page bar, toolbar, main content, action bar, right panel, sub-toolbar).
  • Section = a labeled group inside an area (a <FormSection>, <ContentSection>, or right-panel <CollapsibleSection>).
  • Row = a single item inside a section (one setting, one list entry, one property, one activity event).

Every template below specifies its areas in a table — name, purpose, required elements, optional elements. Then the second half of this file is a row-pattern catalog: every canonical way to present a single piece of information.


Per-template area tables

Type 1 — List page (default)

The most common page in any app — /agents, /tools, /review, /audit.

AreaPurposeRequiredOptional
Page barIdentity, primary create action, scope of the list<ListPageBar title> + entity-plural title<SearchInput> in center slot · primary ”+ New …” action right slot · <ViewSwitcher> (only on task/flow screens)
Content toolbarFilters, secondary search, bulk-action surfaceNone — omit if there’s nothing to filter<FilterChips> · <SearchInput> · sort dropdown · “N selected” + clear (when bulk-active)
MainThe actual collectionOne of: <DataTable> (default) · <CardGrid> (gallery) · <BoardView> (kanban) · calendar/timeline/map per templateEmpty-state variant (zero rows) · loading-state skeleton
FooterPagination + footer aggregates<TablePagination> when N > page sizePer-column footer aggregates (“Total: 1,247”, “Avg: 4.2”) — Attio pattern, not yet in <DataTable> (open issue)
Action barNone on a List page

Forbidden in List. No <ActionBar> (List page has no commit). No persistent right panel (use 3c Drawer if you need one).


A — Dashboard

Landing-page summary. KPI strip on top, charts in middle, detail table at bottom.

AreaPurposeRequiredOptional
Page barTitle + scope (date range)<ListPageBar title="Dashboard"><DateRangePicker> in center · “Export” outline button right slot
Metrics rowAt-a-glance KPIs — the user reads this before anything else<CardGrid columns={4}> of <MetricCard> (label / big number / trend) · 3–6 cards · equal heightsTrend arrow + delta % · sparkline
Charts rowTime-series and breakdownsNone — omit if dashboard is metrics-only<CardGrid columns={2}> of chart cards · max 4 charts before splitting
Detail tableMost-recent activity / drilldown rows<ContentSection> + <DataTable> if dashboard data has rows behind it”View all” link to a List page

Required ordering. Metrics → Charts → Tables, top to bottom. Reordering breaks the “scan → analyze → drill” reading rhythm.


B — Detail 3a Split (record with activity)

Canonical record detail. Left = activity feed; right = persistent property panel. Used on /review/:id, future CRM contact, future agent run detail.

AreaPurposeRequiredOptional
Page barEntity identity, navigation, page-level actions<DetailPageBar backTo title basePath tabs> · back button to parent list · entity name as titlesubtitle (entity description, ≤80 char) · titleEditable / subtitleEditable for inline-edit · primary action right slot
Highlights rowKey stats / status pills above the activity feedNone — optional even on 3a Split<CardGrid columns={3}> of <HighlightCard> (the ONLY cards on this page; max 6)
Main — activity feedReverse-chron timeline of events, comments, status changes<ContentSection title="Activity"> · timeline rows (see Activity row patterns below)Filter chips above the feed (event type) · pagination at bottom (older entries on demand)
Main — notesFree-form notes attached to the recordNone — optional<ContentSection title="Notes" actions={<Button>+</Button>}> · note rows
Right panel — detailsStatic metadata — owner, status, dates, custom fields<RightPanel> with <CollapsibleSection title="Record Details" defaultOpen> containing <PropertyList> of <PropertyRow> · “Show all values” toggle when ≥ 6 rowsMultiple sections (Details, Tags, Lists, Related) · per-section actions slot
Right panel — commentsThreaded comments tied to the record (not the same as activity feed)None — optional second tab in the panelTab bar at top of <RightPanel> switching Details ↔ Comments
Action barNone — 3a Split commits inline (per-property via <InlineEditField>)

Hard rules.

  • Right panel is the second allowed scroll zone (the only exception to “only <PageContent> scrolls”). Each side scrolls independently.
  • Right panel content is flat — no <Card>, no border wrapper. Use <PropertyList> inside <CollapsibleSection>.
  • Highlights are the only cards on this page.

3b — Detail Tabbed full-page

Used by /agents/:id/*. Each tab is a self-contained surface with its own template.

AreaPurposeRequiredOptional
Page barEntity identity + tab bar<DetailPageBar tabs> with ≤ 8 tabs · text-only tab labels · 2px underline active statetitleEditable / subtitleEditable per parent layout doc · primary action right slot
Tab content (Outlet)Fully owned by the active tab — different shape per tab<Outlet /> rendering the per-tab templateSub-toolbar at L4 if a tab needs to switch between equivalent views (per 03-layout.md § Exemptions § Intra-tab sub-navigation)
Action barOptional — per-tab choiceNone at the layout levelPer-tab <ActionBar> for Form-shaped tabs (Settings, Billing)

Hard rules.

  • Tab order is frequency-first (daily-touched leftmost, monthly rightmost).
  • Default tab path is '' (empty path) — don’t use /overview or /details.
  • Layout itself owns no <ActionBar> — each tab decides.

3c — Detail Drawer

The list stays primary; clicking a row opens a slide-over panel. Used for triage (notification inbox, audit log entries).

AreaPurposeRequiredOptional
Drawer headerDrawer title + ✕<SheetHeader> with <SheetTitle> · close buttonPer-record actions in the header (mark read, archive)
Drawer bodyRecord content — read-mostly, denseOne of: read-only detail layout · single short form · property listScroll within the drawer
Drawer footerPer-record commit actionsNone — most drawers are read-onlyFooter with action buttons

Hard rule. Drawer content is ephemeral. URL is backed by ?id=<x> query param so closing the drawer clears it. If the content deserves its own URL and full viewport, promote to 3a Split or 3b Tabbed.


D — Settings (Form, single column)

The dominant template across nx-agent. The example the user called out — many distinct settings, each with its own presentation.

AreaPurposeRequiredOptional
Page barTitle (for standalone settings) OR slim breadcrumb (for tab settings)Standalone: <H1> (24px) inside content + slim <ListPageBar>. Tab: <DetailPageBar> already provides identity.”Save” button NEVER goes here — Save lives in the action bar
Page content (narrow)The form itself — single column, max-w-2xl centered<PageContent narrow> · space-y-10 between sections (40px gap, NOT 24px)
SectionLogical group of related settings<FormSection title description> · description is one sentence per Attio conventionSection-level ”+” or “Reset” outline button (zone ②, never primary)
RowOne setting — see Row patterns catalog belowOne of the 15 canonical row patterns (Toggle / Slider / Input / Select / etc.)Inline <Alert variant="warning"> if a precondition is missing (e.g., “Read KB” toggled but no docs)
Advanced sub-sectionRarely-touched settings hidden by defaultNone — collapse only if the section grows past 6 rows<CollapsibleSection title="Advanced" defaultOpen={false}>
Danger zoneCatastrophic actions, always last on the pageNone — only present if the entity is deletableRed-tinted <Card> (the one card-allowed exception per page) · destructive button + warning copy
Action barSave / Reset commit<ActionBar> as sibling of <PageContent> (NOT inside) · <Button>Cancel</Button> left · <ActionButton>Save</ActionButton> rightCompound action button (“Save and reload agent”) to the left of Save

Hard rules.

  • Section gap is space-y-10 (40px). Spec violation if space-y-6 (24px) per 03-layout.md § Template D.
  • <Separator> between sections is secondary to whitespace — Attio prefers whitespace-only separation. Use <Separator> only when whitespace alone reads ambiguous.
  • Page-bar action variant: outline size="sm" ONLY. Never primary. Save belongs in the action bar.
  • Danger zone is always last. One per page. Red-tinted card.

E — Split form (list-nav + per-item config)

Used when a tab has a list of items (tools, KB docs, channels) and the user picks one to configure.

AreaPurposeRequiredOptional
Sidebar (left, ~30%)Selection only — list of items<SplitContent sidebar> · row per item with hover state · selected row markedSearch / filter <ContentToolbar> above the list
Main (right, ~70%)Configuration form for the selected item<PageContent narrow> inside the main slot · same Form anatomy as Template DEmpty state if nothing selected (“Select an item to configure”)
Action barPer-item Save / Reset<ActionBar> if form-mode (commit-together fields)OMIT if every field is independently savable via <InlineEditField>

Hard rules.

  • Sidebar is selection only. No bulk actions in the sidebar; bulk goes in <ContentToolbar> above.
  • Right side is flat — no nested cards, no right-panel-inside-right-side.
  • Both sides scroll independently — exception to “only PageContent scrolls” is permitted because this is the sidebar-as-nav pattern.

F — Focus wizard

Multi-step linear flow. Sidebar stays visible, body takes over the main pane.

AreaPurposeRequiredOptional
Header row 1Close + breadcrumb (h-12) close button (top-left) · breadcrumb showing “Parent · Step destination”
Header row 2Stepper (h-12, separate row)<Stepper current total> · linear, numbered ① ② ③ ④ · future steps muted
BodyStep content, centered, max-width-constrained<div className="mx-auto max-w-2xl py-12"> containing one or more <FormSection> · bg-background (no tint)Help text · skip-this-step toggle for optional steps
Sticky bottom action barStep navigation<Button variant="ghost">Cancel</Button> left · <Button variant="outline">Previous</Button> middle · <Button>Next</Button> (or “Finish” / outcome verb on last step) right”Skip” link for optional steps

Hard rules.

  • Mount inside AppLayout (sidebar visible). Never overlay the shell.
  • Two-row header. Cramming stepper + close + breadcrumb into one row is forbidden.
  • Body bg is bg-background (same as the rest of the app). No tinted body — focus comes from structure, not color.

G7 — Bulk Import wizard (specialization of F)

Inherits all F areas + a fixed step sequence:

StepBody contentRequired
UploadFile dropzone + format picker (CSV / JSON / Excel)<FileDropZone> · accepted-format hint
MapTwo columns — source columns (left) → target fields (right) · drag or pickList of source columns · target fields with type hints · “Required” marker on must-map fields
PreviewFirst 10 rows rendered as <DataTable> with validation highlightsPer-row error / warning indicator · “N rows have errors” counter
ConfirmSummary: “Import N rows into Y. Errors: Z (skipped). [Start import]""Start import” outcome verb on the action bar
ResultOutcome page — success count + warning drill-down + error drill-down”Close” or “View imported items” actions

G8 — Permissions matrix (specialization of D)

Inherits all D areas + one canonical section content:

ElementPurposeRequired
Matrix headerRoles across the top (sticky)<TableHeader> with one <TableHead> per role
Matrix rowsOne row per resource, cells = checkbox or scope dropdown<TableRow> with resource name in first cell + <Checkbox> (or <Select> for scope) per role cell
Reset to defaultSection-header outline action<Button variant="outline" size="sm">Reset to default</Button> in <FormSection actions>
Action barSticky SaveInherits Template D action bar

Mobile. Matrix degrades to per-role accordion below md — each role becomes an expandable section listing its resources. Side-by-side roles forbidden below md.


G9 — Audit Log (specialization of Type 1 List)

Inherits all Type 1 areas + dense-row override + 3c Drawer for detail:

ElementDifference from default
Row height28px (dense), not 32-40px
Primary actionNone in page bar — audit is read-only. “Export” lives in <ContentToolbar>
Row clickOpens 3c Drawer with full JSON payload pretty-printed in <pre className="font-mono text-xs">
Empty state”No events match these filters” + “Clear filters” — never the blank-slate variant

G10 — Node-Graph Canvas

AreaPurposeRequiredOptional
Toolbar (top)Zoom · Undo / Redo · Run · Publishh-12 shrink-0 toolbar with action buttons”Saved 2s ago” auto-save indicator
Left paletteDraggable node typesVertical list of node tiles · grouped by category · w-56Search field · pinned recent nodes
Canvas (center)Infinite pan/zoom canvas with nodesreact-flow / xyflow surface · node + edge rendering”Drag a node to begin” hint when empty (do NOT use <EmptyState> here)
Right inspectorSelected-node configurationw-80 panel · only mounts when something is selectedTab bar (Properties / Logs / History)
MinimapBird’s-eye view bottom-rightNone — optionalBottom-right corner overlay

Hard rules.

  • No <PageContent> — canvas owns the full body below the toolbar.
  • Save model is C (auto-save 1–2 s debounce). Show “Saved Ns ago” in the toolbar.
  • Read-only mobile fallback below md.

G11 — Editor + Preview

AreaPurposeRequiredOptional
Page barTitle + Run<DetailPageBar> · “Run” primary action right slotSave indicator (Model C auto-save)
Editor (left)Authoring surface — code or prompt editor<SplitContent sidebarWidth="50%"> left side · Monaco / PromptEditorVariables panel above the editor
Preview (right)Live result of the editor’s saved contentRight side of <SplitContent> · renders the latest saved state (not unsaved keystrokes)Loading state during run

Hard rule. Preview reflects the latest saved content, not unsaved keystrokes. Otherwise it flickers and the user can’t tell what’s deployed.


G12 — Auth (Standalone, exempt from AppLayout)

AreaPurposeRequiredOptional
Centered cardThe whole page is one centered card<Card className="w-[400px]"> · brand logo top · <H2> page title · form · footer”Continue with SSO” button + <Separator> divider
Form fieldsEmail, password, or 6-digit codeStacked input rows · full-width primary submit button (the one card-allowed exception)Show/hide password toggle
FooterLegal / forgot password / SSO linkNoneSmall muted links

Hard rule. Full-width buttons are allowed inside the auth card (one of the four card-allowed contexts). Outside auth, full-width buttons remain forbidden.


G13 — Command Palette (Overlay)

AreaPurposeRequiredOptional
Modal shellCentered modal, top-third of viewportPortal-rendered overlay · max-w-2xl · backdrop dim
Search inputAuto-focused on openSingle input at top · placeholder “Search pages, records, actions…”Clear button (X) when text typed
Result groupsGrouped results — Recents, Pages, Records, ActionsEach group has a small muted heading · keyboard-selectable rowsPer-group result limits (“Show all 12 records →“)
Footer hintsKeyboard legend”↑↓ navigate · ↵ select · esc close""⌘K to close” hint

Hard rules.

  • Keyboard-only flow. Mouse works but is slower; never add per-row icons.
  • No destructive actions in the palette (no Delete, no Archive). Open the record first.

Section types and their inner anatomy

Sections are the labeled groups inside areas. Each section type has its own internal anatomy.

<FormSection> (D, E, F)

┌────────────────────────────────────────┐
│ Section title (H4 14px, semibold 600) │ ← required
│ Section description (12px muted) │ ← required for Attio Settings
│ │ ← 24px gap to first row
│ [row 1] │ ← row patterns below
│ [row 2] │
│ … │
└────────────────────────────────────────┘
  • Title. Required. One concept per section (“Voice”, not “Voice & generation”).
  • Description. Required on Settings (Attio convention). One sentence stating what the section governs. NOT optional — every Settings FormSection has one.
  • Field gap. space-y-4 (16px) between rows.
  • Section gap. space-y-10 (40px) between FormSections in the parent stack. NOT space-y-6.
  • Forbidden. <Card> wrapping a <FormSection>. Multiple titles per section.

<ContentSection> (List, Detail, Dashboard)

┌────────────────────────────────────────┐
│ Section title (H3 16px, semibold) │ Section actions → │ ← required
│ │ │
│ [section content — table, grid, etc] │
└────────────────────────────────────────┘
  • Title. Required.
  • Actions. Optional. outline size="sm" only — never primary (primary belongs in page bar).
  • Use cases. Wrapping a <DataTable> with a section title; wrapping a <CardGrid> with “Recent activity” header; wrapping the activity feed in 3a Split.

<CollapsibleSection> (Settings advanced, RightPanel groups)

┌────────────────────────────────────────┐
│ ▾ Section title [actions →] │ ← chevron-clickable
├────────────────────────────────────────┤ ← only when open
│ [content] │
└────────────────────────────────────────┘
  • State persists in localStorage per (pathname, sectionId).
  • Use cases. “Advanced” settings collapsed by default. RightPanel property groups. Variables sub-section in AgentTab.
  • Default open. defaultOpen={true} on first visit if the section is core; defaultOpen={false} for Advanced / rarely-touched.

<RightPanel> content

[Tabs: Details | Comments] ← optional tab bar
┌────────────────────────────────────────┐
│ ▾ Record Details │ CollapsibleSection
│ icon · label │ value │ PropertyRow
│ icon · label │ value │
│ icon · label │ [chip] [chip] │
│ ▸ Show all values │ ShowAllValuesToggle when ≥6 rows
├────────────────────────────────────────┤
│ ▾ Tags │ CollapsibleSection
│ [chip] [chip] [chip] │
└────────────────────────────────────────┘
  • Flat throughout — no <Card> wrappers anywhere in the panel.
  • Tab bar at top is optional; shown when the panel has multiple distinct content modes.

Row patterns catalog

The canonical ways to present a single piece of information within a section. The user’s specific question — “in Attio settings page each setting has a dedicated way to present” — is answered by the Settings rows subsection below.

Settings rows (used in D, E, F-step bodies)

S1 — Toggle row

For boolean settings. Most common Settings row.

Codified primitive: <ToggleRow>. Use the primitive — don’t hand-roll the markup below.

┌────────────────────────────────────────┐
│ Read knowledge base [⚪]│ ← Label left, Switch right
└────────────────────────────────────────┘
<div className="flex items-center justify-between">
<Label htmlFor="kb-toggle">Read knowledge base</Label>
<Switch id="kb-toggle" checked={} onCheckedChange={} />
</div>

When. Boolean, instant-apply (Save Model B). Description below label. Optional — add when the consequence isn’t obvious from the label.

S2 — Toggle row with sub-disclosure

Toggle + when on, reveal nested settings that only matter if the parent is on.

┌────────────────────────────────────────┐
│ Email notifications [🟢]│
│ ┌─ when on ───────────────────────┐ │
│ │ Frequency [Select ▾] │ │
│ │ Include digest [⚪]│ │
│ └────────────────────────────────┘ │
└────────────────────────────────────────┘
<>
<div className="flex items-center justify-between">
<Label htmlFor="notif">Email notifications</Label>
<Switch
id="notif"
checked={enabled}
onCheckedChange={setEnabled}
/>
</div>
{enabled && <div className="mt-4 ml-6 space-y-4 border-l pl-4">{/* nested rows */}</div>}
</>

When. The nested settings are meaningless if the parent is off. Indent. 24px left margin + left border for visual coupling.

S3 — Stacked input row

Free-text single-line value.

┌────────────────────────────────────────┐
│ Display name │ ← Label
│ [_________________________________] │ ← Input
│ Shown on the agent card. │ ← Help text (optional)
└────────────────────────────────────────┘
<div className="space-y-1.5">
<Label htmlFor="name">Display name</Label>
<Input id="name" value={} onChange={} />
<p className="text-muted-foreground text-xs">Shown on the agent card.</p>
</div>

When. Free-text single-line value. Email, URL, name. Help text. Optional. When present, sits below the input. Never use placeholder as label.

S4 — Stacked textarea row

Same as S3 but multi-line.

<div className="space-y-1.5">
<Label htmlFor="bio">Bio</Label>
<Textarea id="bio" rows={4} value={} onChange={} />
</div>

S5 — Select row (1-of-N, N ≥ 4)

Codified primitive: <SelectRow>. Use the primitive — don’t hand-roll. The primitive handles the Attio quiet-label convention by default.

┌────────────────────────────────────────┐
│ Language │
│ [Vietnamese (vi-VN) ▾] │
└────────────────────────────────────────┘
<div className="space-y-1.5">
<Label className="text-muted-foreground text-xs">Language</Label>
<Select value={} onValueChange={}>
<SelectTrigger><SelectValue placeholder="Choose a language" /></SelectTrigger>
<SelectContent>{/* options */}</SelectContent>
</Select>
</div>

When. 1-of-N selection where N ≥ 4 OR the option list is dynamic. Placeholder copy. “Choose a …” not ”— select —”. Label class is text-muted-foreground text-xs when stacked above a Select (matches Attio Settings convention).

S6 — Radio row (1-of-N, N ≤ 4)

┌────────────────────────────────────────┐
│ Theme │
│ ◉ Light │
│ ○ Dark │
│ ○ System │
└────────────────────────────────────────┘

When. 1-of-N where N ≤ 4 AND the user benefits from seeing all options at once.

S7 — Slider row

For continuous numeric values.

Codified primitive: <SliderRow>. The primitive sets aria-valuetext automatically from formatValue + ariaUnit — required a11y comes for free.

┌────────────────────────────────────────┐
│ Speaking rate 1.20× │ ← Label + value display
│ ────●─────────────────────── │ ← Slider full-width
└────────────────────────────────────────┘
<div className="space-y-2">
<div className="flex justify-between text-sm">
<Label>Speaking rate</Label>
<span className="font-medium tabular-nums">{value.toFixed(2)}×</span>
</div>
<Slider min={0.25} max={4} step={0.05} value={[value]} onValueChange={}
aria-valuetext={`${value.toFixed(2)}× speed`} />
</div>

When. Continuous numeric (volume, temperature, threshold). Value display. Right-aligned, font-medium tabular-nums, with unit suffix if applicable (“dB”, ”×”, ”%”). Required a11y. aria-valuetext so screen readers hear “1.20× speed”, not “1.2”.

S8 — Number input row

For discrete numeric (integer counts).

Codified primitive: <NumberInputRow>. Optional suffix prop for units (tokens, ms, MB).

┌────────────────────────────────────────┐
│ Top-K results │
│ [10 ] │
└────────────────────────────────────────┘
<div className="space-y-1">
<Label htmlFor="top-k">Top-K results</Label>
<Input id="top-k" type="number" value={} onChange={} />
</div>

When. Discrete numeric. Counts, IDs. No slider. Sliders are for continuous; counts use Input type=number.

S9 — Avatar / upload row

Profile picture, agent icon, branded asset.

┌────────────────────────────────────────┐
│ ⚪ Avatar │
│ ⚪ [Upload] PNG, JPG · max 2MB │
└────────────────────────────────────────┘
<div className="flex items-center gap-4">
<Avatar className="size-16"><AvatarImage src={} /><AvatarFallback>{}</AvatarFallback></Avatar>
<div className="space-y-1">
<Button variant="outline" size="sm" onClick={}>Upload</Button>
<p className="text-muted-foreground text-xs">PNG, JPG · max 2MB</p>
</div>
</div>

When. Image / avatar setting. Layout. Side-by-side: preview left, upload + constraints right.

S10 — Action row

A “setting” that’s actually a button — performs an operation, doesn’t store a value.

Codified primitive: <ActionRow>. Optional status slot for <MutationStatus> rendered below.

┌────────────────────────────────────────┐
│ Reset to defaults │
│ Restores Voice and Model to factory…│ [Reset]
│ │
└────────────────────────────────────────┘
<div className="flex items-start justify-between gap-4">
<div className="min-w-0 flex-1">
<Label>Reset to defaults</Label>
<p className="text-muted-foreground text-xs mt-0.5">
Restores Voice and Model to factory values.
</p>
</div>
<Button variant="outline" size="sm" onClick={}>Reset</Button>
</div>

When. The “setting” is an operation, not a stored value. “Regenerate API key”, “Reload runtime”, “Resync”. Button variant. outline size="sm". Destructive variant + <ConfirmPopover> if irreversible.

S11 — Info / read-only row

Display a value the user can’t edit, often with a copy button.

┌────────────────────────────────────────┐
│ Agent ID │
│ agt_8a3f2c1d [📋 Copy] │
└────────────────────────────────────────┘
<div className="space-y-1">
<Label>Agent ID</Label>
<div className="flex items-center gap-2">
<code className="text-sm font-mono">{id}</code>
<Button variant="ghost" size="icon-xs" tooltip="Copy" onClick={}>
<Copy />
</Button>
</div>
</div>

When. System-set values, generated tokens, IDs. Code style. font-mono text-sm.

S12 — Date / date-time row

┌────────────────────────────────────────┐
│ Expires on │
│ [Mar 15, 2027 📅] │
└────────────────────────────────────────┘

When. Scheduled tasks, expiration, planned events.

S13 — Color / swatch row

┌────────────────────────────────────────┐
│ Brand color │
│ [⚪][🔴][🟠][🟡][🟢][🔵][🟣][⚫] │ ← swatches as RadioGroup
└────────────────────────────────────────┘

When. Theme color, brand color, status accent. Use a RadioGroup of color swatches, NOT a free-form color picker (use a picker only when the brand requires arbitrary hex).

S14 — Secret / API key row

A read-only row with masking and regenerate.

┌────────────────────────────────────────┐
│ API key │
│ nxa_•••••••••••• [👁][📋][↻] │ ← reveal, copy, regenerate
└────────────────────────────────────────┘

When. Generated secret (API key, webhook signing key). Default state. Masked. Reveal toggles via eye button. Regenerate is destructive — wrap in <ConfirmDialog>.

S15 — Danger row (in Danger Zone)

┌── Danger Zone (red-tinted card) ──────┐
│ Delete agent │
│ Permanently deletes this agent and … │ [Delete agent] ← destructive
└────────────────────────────────────────┘
<Card className="border-destructive/40">
<CardContent className="space-y-4">
<div className="flex items-start justify-between gap-4">
<div>
<Label>Delete agent</Label>
<p className="text-muted-foreground text-xs">Permanently deletes …</p>
</div>
<ConfirmDialog
trigger={<Button variant="destructive" size="sm">Delete agent</Button>}
title="Delete this agent?"
description=""
confirmLabel="Delete"
variant="destructive"
onConfirm={}
/>
</div>
</CardContent>
</Card>

When. Catastrophic actions. Always last on the page. One Danger Zone per page max.


List rows (Type 1, G1, G2 etc.)

L1 — Identity row (DataTable)

☐ [avatar] Name owner@… 2d ago [⋯]
  • Leading checkbox if bulk-selectable.
  • Row hover: hover:bg-muted/50.
  • Whole row clickable to open detail.
  • Trailing actions: max 3 visible icon-xs ghost buttons, rest in <DropdownMenu>.

L2 — Status row

Same as L1 + a status pill column.

☐ [avatar] Name [Active] owner@… 2d ago [⋯]
  • Status uses <StatusBadge> or <Badge> with semantic variant.
┌────────────────┐
│ [thumb] │
│ Name │
│ meta · meta │
└────────────────┘
  • Card 240–320px wide. Hover reveals quick actions overlay.

RightPanel rows (B 3a Split)

R1 — Property row (read-only)

icon · Owner alice@example.com
<PropertyRow
icon={User}
label="Owner"
>
alice@example.com
</PropertyRow>

R2 — Property row with InlineEditField

icon · Domain google.com ← click-to-edit
<PropertyRow
icon={Globe}
label="Domain"
>
<InlineEditField
value={domain}
onCommit={save}
type="url"
/>
</PropertyRow>

R3 — Property row with chips/tags

icon · Tags [Design] [System] [+ 2]

R4 — Show-all-values toggle

▸ Show all values ← bottom of the PropertyList when ≥ 6 rows total

Toolbar rows (above tables / lists)

T1 — Filter chip row

[+ Filter] [Status: Active ✕] [Owner: me ✕] … [Clear all]

T2 — Search + filter + sort

[🔍 Search…] [Filter ▾] [Sort: Recent ▾]

T3 — Bulk action toolbar

3 selected · [Clear] [Tag…] [Archive] [⋯ More]
  • Renders in place of T1/T2 when selection ≥ 1.
  • Sticky on scroll.

Activity feed entries (B 3a Split main)

A1 — Status change

[avatar] alice changed Status to "Active" 2h ago

A2 — Comment / note

[avatar] alice 3h ago
Lorem ipsum dolor sit amet…
[Reply] [Edit] [Delete]

A3 — Email entry

[avatar] alice → bob · "Subject line" Yesterday
Body preview… [Expand]

A4 — System event

[icon] Tools updated 2d ago
5 tools added, 2 removed.

Required-elements global rules

A summary of what every area MUST have, regardless of template:

  1. Page bar — title (entity-plural for List, entity-name for Detail, fixed string for Form/Dashboard). Max 1 primary action.
  2. Every section — one title (H3 or H4). On Settings, also one description sentence.
  3. Every interactive element<Label> (or aria-label) + accessible name. Icon-only buttons MUST have tooltip or aria-label.
  4. Every list — empty state, loading skeleton, and error state. Three states; never fewer.
  5. Every form<ActionBar> as sibling of <PageContent> (NOT inside) + dirty-nav guard if there are unsaved changes worth protecting.
  6. Every multi-step flow — confirm-on-discard on EVERY exit path (✕, Cancel, Esc, sidebar click). Silent no-ops are forbidden (06-flows.md § Exit-path close behavior).
  7. Every destructive action<ConfirmPopover> (routine) or <ConfirmDialog> (catastrophic). Never window.confirm.
  8. Every mutation — feedback per 05-patterns.md § Feedback. Inline <ActionButton> for click-triggered, toast for background events. Never both.

If any of these are missing, the screen is wrong — even if it “looks fine”.


Composition example — AgentTab read against this doc

To make this concrete: the Settings tab at /agents/:id is Template D. Map it to row patterns:

SectionRowPatternWhy
VoiceLanguageS5 Select1-of-2 today, will grow → Select
VoiceVoice (specific)S5 Select1-of-N dynamic
VoiceSpeaking rateS7 Slidercontinuous 0.25–4×
VoicePitchS7 Slidercontinuous −20 to +20
VoiceVolumeS7 Slidercontinuous −10 to +10 dB
VoiceTest voiceS10 Action rowoperation, not a stored value (collapsed into the section without label/desc shape since it’s the section’s outcome — minor variant)
Knowledge & toolsRead knowledge baseS1 Toggleboolean
Knowledge & toolsCall external toolsS1 Toggleboolean
Knowledge & toolsTop-K resultsS8 Number inputdiscrete count
Knowledge & toolsSimilarity thresholdS7 Slidercontinuous 0–1
Knowledge & toolsRerankingS1 Toggleboolean
ModelLLM modelS5 Select1-of-many
ModelEmbedding modelS5 Select1-of-many
ModelTemperatureS7 Slidercontinuous 0–1
ModelMax tokensS8 Number inputdiscrete count
Variables (collapsible)each variableL1 Identity rowlisted in a sub-DataTable

Each row has a defined pattern. No improvisation. That’s the discipline this doc codifies.


Next: jump back to 11-templates-catalog.md for “which template do I pick”, or 04-components.md for primitive APIs.