Skip to content

Layout

One shell, two page shapes, and the widths, rails and gutters that frame every screen.

One shell#

Every Oration app sits in the same frame: a cool-neutral sidebar rail beside the white content plane, and a 48px app header on top of every workspace page.

The shell at each sidebar state

Drawn at real size and scaled to fit. The sidebar collapses to an icon rail on request and becomes a sheet below 768px.

Shell measurements
PartSizeNotes
Sidebar rail16remCool Rail (bg-sidebar), 28px items in Body dense, 16px icons with a 10px gap. Read from SIDEBAR_WIDTH in the Sidebar component.
Icon rail3remThe collapsed sidebar. Items show only their icons.
Sheet below 768px18remThe sidebar opens over the plane from the header's toggle, on the dialog scrim.
App header48pxSticky, White Plane with a hairline bottom, 12px side padding. Holds the sidebar toggle, a 16px divider, breadcrumbs and page actions 6px apart.

The header is the one constant. Document pages scroll under it; full-bleed tools sit beneath it and scroll inside. Pages without a visible title pass heading to the header so it renders the page's h1 as screen-reader text. See Sidebar and Breadcrumb.

Two page shapes#

Inside the shell, a page is either a document that scrolls or a tool that fills the viewport. Decide which before drawing anything.

Document pages#

Home, settings, overviews and record pages. A centered column up to 72rem that scrolls with the window.

Document page measurements
MeasureValueClasses
Column width72rem (1152px)mx-auto w-full max-w-6xl
Narrow forms48rem (768px)max-w-3xl
Side gutters24px, 16px below 640pxpx-4 sm:px-6
Top and bottom padding32pxpy-8
Between sections32pxgap-8 or mt-8
Page descriptionup to 42remmax-w-[42rem]
A document page
// A document page: Home, settings, overviews, record tabs<AppHeader crumbs={[{ label: "Payments" }, { label: "Payment runs" }]} /><div className="mx-auto w-full max-w-6xl px-4 py-8 sm:px-6">  <PageTitle    title="Payment runs"    description="Schedule, approve and reconcile supplier payments."  />  <div className="mt-8 flex flex-col gap-8">    <section>…</section>    <section>…</section>  </div></div>// A narrow form keeps the gutters and caps the column at 48rem<div className="mx-auto w-full max-w-3xl px-4 py-8 sm:px-6">…</div>

PageBody in Page title is max-w-6xl px-6 py-8, so it keeps 24px gutters on a phone. DESIGN.md asks for 16px below 640px, which is what Home and the hand-built document pages use. Write px-4 sm:px-6 until PageBody changes.

Full-bleed tools#

Grids, boards, canvases and editors. A full-height column where one region scrolls and the chrome around it stays put.

Full-bleed tool measurements
PartValueNotes
Column100svhflex h-svh min-h-0 flex-col. The window never scrolls.
App header48pxThe same sticky header as every page.
Toolbar rows28px controlsView tabs, search, filters, sort and display in one or two rows. See Toolbar.
Contentflex-1One region that scrolls internally: min-h-0 flex-1 overflow-auto. Grid headers stick to its top.
Footer36pxSticky, with counts and totals in 12px tabular figures.
A full-bleed tool
// A full-bleed tool: grids, boards, canvases, editors<div className="flex h-svh min-h-0 flex-col">  <AppHeader heading="Invoices" crumbs={[{ label: "Invoices" }]} />  <Toolbar>…28px controls…</Toolbar>  <div className="min-h-0 flex-1 overflow-auto">    <DataGrid … />  </div>  <footer className="sticky bottom-0 flex h-9 items-center border-t border-border px-3 text-xs text-muted-foreground tabular-nums">    212 invoices, $1,284,920.18  </footer></div>
  • A page has one scrolling region. Nested scroll areas inside a scrolling page are a sign the page picked the wrong shape.
  • Don't center a tool in a 72rem column, and don't stretch a document page edge to edge.
  • min-h-0 on every flex child between the column and the scrolling region, or the region grows instead of scrolling.

Home#

A document page with a two-column grid from 1024px: the approvals column plus a 20rem right rail.

Columns sit 32px apart and rail cards 16px apart. Below 1024px the rail moves above the approvals and sits two-up from 768px. The rail comes first in the source, so it is also first for keyboard and screen-reader users at every width.

The Home grid
// apps/web/src/app/(app)/page.tsx<div className="mx-auto w-full max-w-6xl px-4 py-8 sm:px-6">  <HomeGreeting />  <div className="mt-8 grid gap-8 lg:grid-cols-[minmax(0,1fr)_20rem] lg:gap-y-4">    <aside className="grid content-start gap-4 md:grid-cols-2 lg:col-start-2 lg:row-start-1 lg:grid-cols-1">      …rail cards…    </aside>    <div className="min-w-0 lg:col-start-1 lg:row-span-2 lg:row-start-1">      <ApprovalsQueue />    </div>  </div></div>

Record pages#

A record page adds a 21rem attribute rail on the right from 1024px, and its tab bar sticks under the header.

Record page measurements
PartValueNotes
Attribute rail21remw-[21rem] border-l border-border, scrolling on its own. A hairline edge, not a shadow: the rail is part of the plane.
Tab barline tabsSticks under the header, scrolls horizontally and fades its clipped edge over 2rem.
Below 1024pxsheetThe rail moves into a right sheet opened from a details button in the header.

All measurements#

Every fixed width and height in the frame, in one place.

Layout measurements
ElementSizeTailwind
Sidebar16rem--sidebar-width
Icon rail3rem--sidebar-width-icon
Sidebar sheet below 768px18rem--sidebar-width on mobile
App header48pxh-12
Document column72remmax-w-6xl
Narrow form column48remmax-w-3xl
Reading text and descriptions42remmax-w-[42rem]
Gutters24px (16px below 640px)px-4 sm:px-6
Page top and bottom32pxpy-8
Between sections and Home's columns32pxgap-8
Home rail20remlg:grid-cols-[minmax(0,1fr)_20rem]
Between rail cards16pxgap-4
Record attribute rail21remw-[21rem]
Toolbar controls28pxh-7
Tool footer36pxh-9

Templates#

Each template is one of the two shapes with its parts filled in. Start a new screen from the closest one.

Templates by page shape
TemplateShapeWhat it adds
Document pageDocumentTitle, description and sections in the 72rem column.
HomeDocumentThe greeting, the approvals column and the 20rem rail.
Settings pageDocumentSettings navigation, sections of label-left rows and the save bar.
Record pageDocumentA sticky line tab bar and the 21rem attribute rail.
List pageToolToolbar, data grid and the sticky footer.
WorkspaceToolQueue, conversation and context panes that collapse to one below 768px.
CanvasToolA node canvas on the dotted grid with a palette and an inspector.
AuthOutside the shellCentered and split layouts for sign in and sign up, with no sidebar or header.