Object Page Cards
One padded card shell for Object Page body regions — titles, dividers, Descriptions layout, and toolbar control height.
Use this page for Object Page specifics: Descriptions layout, Related List body padding, and toolbar control height. The shell, title, and rhythm tokens are cross-page and live in Page Sections — this page does not redefine them.
Object Page body cards share one padded shell, two title weights, and one toolbar control height. Do not mix a flush-table Related List with a padded Notes card on the same page.
When To Use
- Wiring Attachments, Activity, Line items, or Related List cards on an Object Page.
- Choosing card title vs in-card muted group headings.
- Fixing mixed density (flush table + padded Notes) or title-row
size="sm"tools.
The Rule
SectionCard / RelatedList own the card title. Padding is p-6. Title→body air is gap-4, not a hairline. Toolbar controls are default h-8.
Shell
SectionCard is the shell — do not hand-roll the classes, and do not render a title next to it:
<SectionCard title="Attachments" actions={<Button>Add attachment</Button>}>
<AttachmentsTable />
</SectionCard>Padding, title type, page gap, and group rhythm are defined once in Page Sections § Type Ladder and § Rhythm. Object Page adds only these:
| Token | Value | What to do |
|---|---|---|
Related List bodyPadding | default | Shares card p-6. "none" (-mx-6 -mb-6) is escape hatch only — not the Table recipe. |
| Header summary | content + extraContent | Do not stuff a page Alert into the left content column beside Amount |
Descriptions bordered | Never inside a card | It paints a second card (p-4 + extra border). The host owns the shell; Descriptions is unbordered content. |
The problem this prevents is mixed density: header padded with px-6, table flush with p-0, and a border-b hairline pretending to be title→body air.
Titles
The problem is treating every heading as the same muted GroupHeading. A card that owns one topic (Attachments, Activity, Line items) uses the shell's title. Peer groups inside one card (Contact, Fulfillment, Notes) stay muted SectionGroupHeading.
| Role | Where | When |
|---|---|---|
| Card title | SectionCard / RelatedList title prop | Attachments, Activity, Line items |
| In-card group | SectionGroupHeading (muted) | Contact, Fulfillment, Notes inside a shared card |
Descriptions title | Do not pass on Object Page | The card owns the title |
One title owner. Related List owns the card title (title + optional count) — do not wrap it in another group heading. Do not pass Descriptions.title when the field grid already sits in the card. Notes that share a card with Addresses stay muted — do not upgrade Notes to match Attachments.
Copy is sentence case (Line items, Add attachment) — Sentence Case. No CSS uppercase.
Dividers
The problem is a border-b under the card title (Ant Card head). That hairline is a second language next to padded Notes / DetailCard. Title→table air is gap-4, not a line.
Separator only between in-card groups. No border-b under the card title. Title→table air is gap-4.
Use a Separator | Do not |
|---|---|
| Between in-card groups (Contact then Fulfillment) | Under the card title (border-b on the toolbar) |
| — | Between title and Table/List — that air is gap-4 |
ASCII diagrams that draw a line under the title mean “next row is the body”, not a CSS hairline.
Descriptions Layout
Do not reopen the kit default. Cite CRUD Page Patterns — Descriptions Layout And Header KPIs: short scalars horizontal; Notes/addresses vertical; kit default stays vertical; header KPIs are Statistic.
| Body | layout |
|---|---|
| Short scalars (Contact, Fulfillment, status, dates, money codes) | horizontal |
| Long text (Notes, addresses, multi-line) | vertical (or wider span) |
| Kit default | vertical — do not flip |
| Page-header Amount / Quantity | Statistic, never Descriptions hero type |
Empty field values use EmptyValuePlaceholder — not region Empty.
Region Toolbar Controls
The problem is mixing SelectTrigger size="sm" / Button size="sm" (h-7) with default Buttons (h-8) on the same title row. Default height is h-8. Do not put SelectTrigger size="sm" or Button size="sm" on the title row (including Demo status teaching controls). Tools ghost/outline; at most one solid Add. See CRUD Region Table Toolbar and Button And Action Emphasis.
| Rule | Lock |
|---|---|
| Height | Default h-8. Button, SelectTrigger, outline Columns, solid Add — same height |
| Ban | SelectTrigger size="sm" and Button size="sm" in this row |
| Emphasis | Tools ghost/outline; at most one solid (region Add) |
| Layout | Horizontal cluster on the same row as the title; no floating vertical stack |
Popover footers inside Columns (Reset / Save) may stay size="sm" — those are overlay chrome, not the card toolbar.
Examples
Padded Card Vs Flush Table
Left side is the flush-table recipe: muted title, hairline under the toolbar, size="sm" Columns, table flush to the card edge. Right side is SectionCard — p-6 padding, 16px semibold title in the shell's own title slot, default-height tools, table inset with gap-4.
Wrong
Attachments
| File | Uploaded |
|---|---|
| po.pdf | 2026-03-01 |
Right
Attachments
| File | Uploaded |
|---|---|
| po.pdf | 2026-03-01 |
"use client";
import { SectionCard } from "@/components/f-ui/section-card/section-card";
import { Button } from "@/components/ui/button";
import { DesignCompare } from "@/demos/_design/design-compare";
function MiniTable() {
return (
<table className="w-full text-sm">
<thead>
<tr className="text-muted-foreground text-xs">
<th className="px-2 py-2 text-left font-medium">File</th>
<th className="px-2 py-2 text-left font-medium">Uploaded</th>
</tr>
</thead>
<tbody>
<tr className="border-t">
<td className="px-2 py-2">po.pdf</td>
<td className="px-2 py-2">2026-03-01</td>
</tr>
</tbody>
</table>
);
}
export function ObjectPageCardsShellDemo() {
return (
<DesignCompare
wrong={
<div className="bg-card overflow-hidden rounded-xl border">
<div className="flex items-center justify-between border-b px-6 py-3">
<h2 className="text-muted-foreground text-sm font-medium">Attachments</h2>
<div className="flex items-center gap-2">
<Button type="button" variant="outline" size="sm">
Columns
</Button>
<Button type="button">Add attachment</Button>
</div>
</div>
<MiniTable />
</div>
}
right={
<SectionCard
title="Attachments"
tools={
<Button type="button" variant="outline">
Columns
</Button>
}
actions={<Button type="button">Add attachment</Button>}
>
<MiniTable />
</SectionCard>
}
/>
);
}Checklist
- Body cards use
SectionCard/RelatedListwith thetitleprop — no heading rendered as an outside sibling (Page Sections). - Object Page body cards follow this page — not a flush-table recipe.
- CRUD Page Patterns and Related List link here; Region Table Toolbar diagrams do not teach a
border-bunder the title. - /showcases/orders-detail-related: in-card groups muted; Attachments / Activity semibold; same
p-6+gap-4; Demo status / Columns / Add allh-8. - /showcases/orders-detail: Line items title matches Attachments weight; Notes/addresses vertical.
- /showcases/orders-detail-basic: one card, muted groups,
Separatorbetween groups,gap-4. - /showcases/approvals-detail: persona Alert is a body sibling; cards are direct
PageContainerchildren; noDetailCardgap-*override. - Related List stays on the padded shell;
bodyPadding="none"is escape hatch only. Fill-height preview usesSectionCard fitHeight, not Related List. - No Object Page
Descriptions bordered; no title-rowsize="sm".
See Also
- Page Sections — cross-page shell, title ladder, and rhythm
- CRUD Page Patterns — Body Card Granularity, Descriptions layout, Region Table Toolbar
- Related List
- Sentence Case
- Button And Action Emphasis
- Page And Region Status