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.
The three wrappers
Section titled “The three wrappers”| Wrapper | When | Examples |
|---|---|---|
WorkspacePage | Split-view apps with custom panels/sidebars | Chat, Comms, Tasks (split view) |
StandardPage | Default — header + content grid | App Store, Admin, Projects, Brain |
ControlPage | Settings / configuration forms | Settings, Billing, Admin → Feature Flags |
When unsure, use StandardPage.
What each wrapper does
Section titled “What each wrapper does”WorkspacePage
Section titled “WorkspacePage”<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-6on inner panels - AppBreadcrumb mounted at top
- Common pattern: 3-column with left sidebar (list), middle (detail), right rail (Sidekick or metadata)
StandardPage
Section titled “StandardPage”<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-6automatically - Best for list views, detail views, dashboards
- Used by ~80% of pages
ControlPage
Section titled “ControlPage”<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
Rail-to-rail layout (NON-NEGOTIABLE)
Section titled “Rail-to-rail layout (NON-NEGOTIABLE)”Two invisible vertical rails run through every screen — defined by UnifiedHeader’s px-4 md:px-6. Every layer below must align:
| Rule | Why |
|---|---|
NEVER max-w-* / mx-auto / .container on outer wrapper | Pushes content away from rails |
max-w-* ONLY on inner elements where line-length matters | Long-form text, forms, conversation threads |
StandardPage.Content provides w-full px-4 md:px-6 automatically | Don’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 exception | Forms need readability constraint |
Never px-3 / px-5 / px-8 / bare px-6 as outer edge | Breaks rail alignment |
AppBreadcrumb integration
Section titled “AppBreadcrumb integration”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.
Vertical rhythm
Section titled “Vertical rhythm”Three spacing levels only:
gap-6/space-y-6(24px) — between major page sectionsgap-3/space-y-3(12px) — within a sectiongap-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.
Page loading states (NON-NEGOTIABLE)
Section titled “Page loading states (NON-NEGOTIABLE)”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">