Page Composition
Overview
Decide how pages are assembled from components: layout grid, page templates, responsive collapse strategy, navigation transformation per breakpoint, and content priority rules. Output is .forge/page-composition.md. Reads component-library (available pieces), design-system (breakpoints + spacing), and interaction-patterns (scroll, sticky, overlay behavior).
When to Use
- A product is about to start building pages and there's no named template vocabulary
- Routes have drifted into one-off layouts with no shared structure
- The sidebar collapses inconsistently on mobile (or doesn't collapse at all)
- A new responsive breakpoint is being added and nobody knows what should change
- A second product is joining the design system and needs to inherit layout conventions
When NOT to Use
- A single one-off marketing page — that's content, not composition
- Backend-only services with no UI
- A trivial layout fix inside one route —
incremental-implementation
Common Rationalizations
| Thought |
Reality |
| "Every page is different" |
Every page feels different, but most follow 3–4 templates. Name them and variation becomes predictable. |
| "We'll figure out responsive as we go" |
"As we go" means the first 5 pages are desktop-only and mobile is retrofitted on day 10 under deadline pressure. |
| "Just make it responsive with Tailwind" |
Tailwind handles the mechanics (sm:, md:, lg:). It doesn't decide what to do at each breakpoint. That's a design decision. |
| "Mobile can wait" |
If field users open the product on phones, mobile IS the product. Desktop is the secondary experience. |
| "Sticky elements just work" |
A sticky header that covers content on mobile is a bug. Sticky needs a rule. |
Red Flags
- A route with no defined template (a one-off layout)
- A sidebar that doesn't collapse on mobile (or hides instead of relocating)
- Content that disappears on small screens rather than relocating to a secondary tab/accordion
- Inconsistent grid usage across routes (12-col on one, free-flow on another)
- Scroll behavior differing between similar pages (infinite on one list, paginated on the next)
- Sticky element that covers content on mobile (header overlapping first row of a list)
Core Process
Step 1: Read upstream artifacts
Read .forge/component-library.md (available components), .forge/design-system.md (breakpoints + spacing scale + max content width), .forge/interaction-patterns.md (scroll, sticky, overlay rules). Confirm the breakpoint set before defining templates against it.
Step 2: Layout system
Define the grid that every template inherits:
- Grid: 12-column, 8-column, or flexbox-based. Pick one product-wide.
- Gutter: from the
design-system spacing scale (e.g., 16px mobile, 24px desktop).
- Max content width: the cap beyond which content doesn't grow on ultra-wide screens (e.g.,
1280px for dashboards, 1440px for tables, 640px for forms).
- Edge padding per breakpoint: how much breathing room from the viewport edge at each size.
Step 3: Name page templates
List the recurring page shapes the product uses. Common templates (include only what's needed):
- Dashboard: metrics row → charts grid → activity feed. Sidebar on desktop, bottom nav on mobile.
- Detail: hero/header → key metrics → content tabs → action footer. Full-width on mobile.
- List: filter bar → sortable table or card list → pagination. Cards on mobile, table on desktop.
- Form: section groups → inputs → sticky action bar. Single column always.
- Settings: sidebar nav → content panel. Tabs on mobile.
- Empty: illustration + headline + description + CTA. Centered always.
Step 4: Define each template
For every template, document:
- Section hierarchy — what comes first, second, third
- Information density per breakpoint — desktop shows 3 columns of cards, tablet 2, mobile 1
- Sticky elements — header, action bar, sidebar; offsets so they don't cover content
- Scroll behavior — infinite scroll vs pagination vs load-more, per template (not per page)
- Responsive collapse strategy — what happens to the sidebar, what happens to the grid, what gets hidden vs stacked vs tabified
Step 5: Responsive philosophy (per product)
Decide once, product-wide:
- Mobile-first (field reps, consumer apps): design at 380px first, enhance for desktop. Mobile is THE product.
- Desktop-first (SaaS managers, admin tools): design at 1280px first, adapt for mobile. Desktop is THE product.
This is a per-product decision, not a per-page decision. State it explicitly in the artifact.
Step 6: Navigation transformation
Document how navigation changes across breakpoints:
| Breakpoint |
Primary nav |
Secondary nav |
Desktop (lg+) |
Sidebar (expanded) + topbar |
Inline in topbar |
Tablet (md) |
Sidebar (collapsed to icons) + topbar |
Inline in topbar |
Mobile (sm) |
Bottom tabs (3–5 items) |
Hamburger overflow menu |
Define each breakpoint transition explicitly. No implicit "the sidebar will figure it out."
Step 7: Content priority rules
On mobile, content does not disappear — it relocates. Document the rules:
- Primary content stays in the main flow
- Secondary content collapses into an expandable section or moves to a separate tab
- Tertiary content moves to a "More" overflow menu
- Decorative content (avatars in tables, illustrations) shrinks or hides — explicitly mark which
The principle: every piece of information has a home at every breakpoint. Nothing vanishes.
Step 8: Write .forge/page-composition.md
Sections in this order: upstream-read confirmation, layout system, template catalog, per-template specs, responsive philosophy, navigation transformation, content priority rules. Prepend a forge:meta header (generated_by: page-composition, generated_at: <ISO 8601 UTC with Z>, depends_on: [.forge/component-library.md, .forge/design-system.md, .forge/interaction-patterns.md] — paths only, never hashes, generated_from: {.forge/component-library.md: <hash>, .forge/design-system.md: <hash>, .forge/interaction-patterns.md: <hash>} — each upstream's content_hash AT generation time, content_hash: <sha256 first 8 of THIS file's body>).
Verification
1---2name: page-composition3description: Use when defining how pages are assembled from components, when establishing layout grids, when deciding responsive collapse strategies, or when multiple routes have inconsistent layouts.4---56# Page Composition78## Overview910Decide how pages are assembled from components: layout grid, page templates, responsive collapse strategy, navigation transformation per breakpoint, and content priority rules. Output is `.forge/page-composition.md`. Reads `component-library` (available pieces), `design-system` (breakpoints + spacing), and `interaction-patterns` (scroll, sticky, overlay behavior).1112## When to Use1314- A product is about to start building pages and there's no named template vocabulary15- Routes have drifted into one-off layouts with no shared structure16- The sidebar collapses inconsistently on mobile (or doesn't collapse at all)17- A new responsive breakpoint is being added and nobody knows what should change18- A second product is joining the design system and needs to inherit layout conventions1920## When NOT to Use2122- A single one-off marketing page — that's content, not composition23- Backend-only services with no UI24- A trivial layout fix inside one route — `incremental-implementation`2526## Common Rationalizations2728| Thought | Reality |29|---------|---------|30| "Every page is different" | Every page feels different, but most follow 3–4 templates. Name them and variation becomes predictable. |31| "We'll figure out responsive as we go" | "As we go" means the first 5 pages are desktop-only and mobile is retrofitted on day 10 under deadline pressure. |32| "Just make it responsive with Tailwind" | Tailwind handles the mechanics (`sm:`, `md:`, `lg:`). It doesn't decide *what* to do at each breakpoint. That's a design decision. |33| "Mobile can wait" | If field users open the product on phones, mobile IS the product. Desktop is the secondary experience. |34| "Sticky elements just work" | A sticky header that covers content on mobile is a bug. Sticky needs a rule. |3536## Red Flags3738- A route with no defined template (a one-off layout)39- A sidebar that doesn't collapse on mobile (or hides instead of relocating)40- Content that disappears on small screens rather than relocating to a secondary tab/accordion41- Inconsistent grid usage across routes (12-col on one, free-flow on another)42- Scroll behavior differing between similar pages (infinite on one list, paginated on the next)43- Sticky element that covers content on mobile (header overlapping first row of a list)4445## Core Process4647### Step 1: Read upstream artifacts4849Read `.forge/component-library.md` (available components), `.forge/design-system.md` (breakpoints + spacing scale + max content width), `.forge/interaction-patterns.md` (scroll, sticky, overlay rules). Confirm the breakpoint set before defining templates against it.5051### Step 2: Layout system5253Define the grid that every template inherits:5455- **Grid:** 12-column, 8-column, or flexbox-based. Pick one product-wide.56- **Gutter:** from the `design-system` spacing scale (e.g., `16px` mobile, `24px` desktop).57- **Max content width:** the cap beyond which content doesn't grow on ultra-wide screens (e.g., `1280px` for dashboards, `1440px` for tables, `640px` for forms).58- **Edge padding per breakpoint:** how much breathing room from the viewport edge at each size.5960### Step 3: Name page templates6162List the recurring page shapes the product uses. Common templates (include only what's needed):6364- **Dashboard:** metrics row → charts grid → activity feed. Sidebar on desktop, bottom nav on mobile.65- **Detail:** hero/header → key metrics → content tabs → action footer. Full-width on mobile.66- **List:** filter bar → sortable table or card list → pagination. Cards on mobile, table on desktop.67- **Form:** section groups → inputs → sticky action bar. Single column always.68- **Settings:** sidebar nav → content panel. Tabs on mobile.69- **Empty:** illustration + headline + description + CTA. Centered always.7071### Step 4: Define each template7273For every template, document:7475- **Section hierarchy** — what comes first, second, third76- **Information density per breakpoint** — desktop shows 3 columns of cards, tablet 2, mobile 177- **Sticky elements** — header, action bar, sidebar; offsets so they don't cover content78- **Scroll behavior** — infinite scroll vs pagination vs load-more, per template (not per page)79- **Responsive collapse strategy** — what happens to the sidebar, what happens to the grid, what gets hidden vs stacked vs tabified8081### Step 5: Responsive philosophy (per product)8283Decide once, product-wide:8485- **Mobile-first** (field reps, consumer apps): design at 380px first, enhance for desktop. Mobile is THE product.86- **Desktop-first** (SaaS managers, admin tools): design at 1280px first, adapt for mobile. Desktop is THE product.8788This is a per-*product* decision, not a per-page decision. State it explicitly in the artifact.8990### Step 6: Navigation transformation9192Document how navigation changes across breakpoints:9394| Breakpoint | Primary nav | Secondary nav |95|---|---|---|96| Desktop (`lg+`) | Sidebar (expanded) + topbar | Inline in topbar |97| Tablet (`md`) | Sidebar (collapsed to icons) + topbar | Inline in topbar |98| Mobile (`sm`) | Bottom tabs (3–5 items) | Hamburger overflow menu |99100Define each breakpoint transition explicitly. No implicit "the sidebar will figure it out."101102### Step 7: Content priority rules103104On mobile, content does **not disappear** — it relocates. Document the rules:105106- Primary content stays in the main flow107- Secondary content collapses into an expandable section or moves to a separate tab108- Tertiary content moves to a "More" overflow menu109- Decorative content (avatars in tables, illustrations) shrinks or hides — explicitly mark which110111The principle: every piece of information has a home at every breakpoint. Nothing vanishes.112113### Step 8: Write `.forge/page-composition.md`114115Sections in this order: upstream-read confirmation, layout system, template catalog, per-template specs, responsive philosophy, navigation transformation, content priority rules. Prepend a `forge:meta` header (`generated_by: page-composition`, `generated_at: <ISO 8601 UTC with Z>`, `depends_on: [.forge/component-library.md, .forge/design-system.md, .forge/interaction-patterns.md]` — paths only, never hashes, `generated_from: {.forge/component-library.md: <hash>, .forge/design-system.md: <hash>, .forge/interaction-patterns.md: <hash>}` — each upstream's content_hash AT generation time, `content_hash: <sha256 first 8 of THIS file's body>`).116117## Verification118119- [ ] Every route in the product maps to a named template (or is documented as one-off with reason)120- [ ] Every template has responsive behavior at all `design-system` breakpoints121- [ ] Navigation transformation is documented per breakpoint122- [ ] Content priority rules exist — nothing disappears, it relocates123- [ ] Mobile-first vs desktop-first decided once, product-wide124- [ ] Layout grid, gutter, max content width, and edge padding documented125- [ ] Sticky elements have offsets that don't cover content on the smallest breakpoint126- [ ] Scroll behavior is template-level, not per-page127- [ ] `.forge/page-composition.md` written with `forge:meta` header