Skip to content

Page Layout Wrappers (NON-NEGOTIABLE)

Every page MUST use WorkspacePage, StandardPage, or ControlPage. Three layouts cover 100% of cases. Custom layouts are how design coherence dies.

Every new page MUST use one of three wrappers from @/components/layout/page-wrappers. Three layouts cover 100% of cases. Custom layouts are how design coherence dies.

WrapperWhenExamples
WorkspacePageSplit-view apps with custom panels/sidebarsChat, Comms, Tasks (split view)
StandardPageDefault — header + content gridApp Store, Admin, Projects, Brain
ControlPageSettings / configuration formsSettings, Billing, Admin → Feature Flags

When unsure, use StandardPage.

<WorkspacePage>
{/* You compose your own panels — left sidebar, middle, right rail */}
</WorkspacePage>
  • Shell that takes the full viewport
  • You’re responsible for px-4 md:px-6 on inner panels
  • AppBreadcrumb mounted at top
  • Common pattern: 3-column with left sidebar (list), middle (detail), right rail (Sidekick or metadata)
<StandardPage>
<StandardPage.Content>
{/* Your page body — automatically gets px-4 md:px-6 */}
</StandardPage.Content>
</StandardPage>
  • Header with AppBreadcrumb
  • Content area w-full px-4 md:px-6 automatically
  • Best for list views, detail views, dashboards
  • Used by ~80% of pages
<ControlPage>
{/* Settings form content — narrow centered max-w-4xl */}
</ControlPage>
  • Header with AppBreadcrumb
  • Content area is narrow (max-w-4xl, centered) — intentional readability constraint for forms
  • Only place where max-w-* is OK on the outer wrapper

Two invisible vertical rails run through every screen — defined by UnifiedHeader’s px-4 md:px-6. Every layer below must align:

RuleWhy
NEVER max-w-* / mx-auto / .container on outer wrapperPushes content away from rails
max-w-* ONLY on inner elements where line-length mattersLong-form text, forms, conversation threads
StandardPage.Content provides w-full px-4 md:px-6 automaticallyDon’t double-pad
WorkspacePage is a shell — add px-4 md:px-6 to your inner content manually
ControlPage max-w-4xl is the ONE intentional exceptionForms need readability constraint
Never px-3 / px-5 / px-8 / bare px-6 as outer edgeBreaks rail alignment

All wrappers mount AppBreadcrumb at the top automatically. App-specific header controls go in the AppBreadcrumb actions slot.

The UnifiedHeader Z3/Z4/Z5 zones are deprecated. Don’t use setZ3/setZ4/setZ5 in new pages.

Three spacing levels only:

  • gap-6 / space-y-6 (24px) — between major page sections
  • gap-3 / space-y-3 (12px) — within a section
  • gap-2 (8px) — between micro-elements (icon + label)

Never mix other gap values on structural layout. gap-4 and space-y-4 are reserved for component-internal use.

NEVER return a bare spinner before the page’s AppBreadcrumb renders. The breadcrumb must always be the first thing visible so the user has context.

Put the loading state INSIDE the content area:

<div className="flex items-center justify-center min-h-[40vh]">
<LoadingIcon className="h-8 w-8 text-muted-foreground" />
</div>

Only exception: the very first !appConfig guard (before any layout is available) can use:

<div className="flex-1 flex items-center justify-center">