Canonical layouts
4 canonical layout templates that cover ~90% of Koder UI screens. Each defines element placement, behavior across window-size classes, and accessibility contract. Material parity (`/foundations/layout/canonical-layouts/{feed,list-detail,supporting-pane}`); composed via `KoderCanonicalLayout` in koder_kit (planned).
Spec — Canonical layouts
Facet *isual*do Koder Design. Material parity: https://m3.material.io/foundations/layout/canonical-layouts/feed (and siblings).
Every Koder screen should fit one of 4 canonical templates. Custom layouts are allowed but require justification in PR review.
L1 — Feed
Vertical scrollable list of homogeneous items. Most common pattern.
Compact (phone): Expanded (desktop):
┌─────────────────┐ ┌────────┬────────┐
│ Item 1 │ │ Item 1 │ Item 2 │
├─────────────────┤ ├────────┼────────┤
│ Item 2 │ │ Item 3 │ Item 4 │
├─────────────────┤ ├────────┼────────┤
│ Item 3 │ │ Item 5 │ Item 6 │
└─────────────────┘ └────────┴────────┘
1 column 2-3 columns (per width)*ules*
- Compact: 1 column, full-width items
- Medium: 1-2 columns depending on item type
- Expanded: 2-3 columns
- Large: 3-4 columns
- Item heights uniform OR card
based with peritem heights - Scroll: vertical only; horizontal carousels nest INSIDE feed items
- Filterssearch above the feed; sort persistent in URLstorage
*se cases* news feed, product list, file browser, email list, notification center, search results.
L2 — List-detail
Two synchronized panes: a list on the left, detail of the selected item on the right.
Compact: Expanded:
┌─────────────────┐ ┌─────┬───────────┐
│ List │ │List │ Detail │
│ ┌─item 1─┐ │ │item │ │
│ │ item 2 │ │ → tap │item*│ selected │
│ └────────┘ │ │item │ content │
│ ... │ │item │ │
└─────────────────┘ └─────┴───────────┘
Stack (full-screen detail) Side-by-side (40/60)*ules*
- Compact: list IS the screen; tapping pushes the detail full-screen
with back navigation per
back-behavior.kmd - Medium: optional split (40/60 if width ≥ 720), else stack like Compact
- Expanded/Large: persistent split (typically 320px list + flex detail)
- Selection state synced (URL deep-link to selected item)
- Empty state in detail when nothing selected (Expanded/Large)
*se cases* settings, chat (conversation list + thread), file explorer, contact book, admin dashboards.
L3 — Supporting pane
Primary content + auxiliary pane (collapsible) that supports the primary content without being navigation.
Compact: Expanded:
┌─────────────────┐ ┌─────────┬───────┐
│ Primary content │ │ Primary │ Aux │
│ │ │ content │ │
│ │ │ │ pane │
│ [Show aux ▼] │ │ │ │
└─────────────────┘ └─────────┴───────┘
Sheet/dialog on demand Persistent right pane (65/35)*ules*
- Compact: aux pane lives in a bottom-sheet or modal triggered by a
button
- Expanded/Large: aux pane persistent on the right (~30-35% width)
- Aux pane is *upportive*(filters, related items, contextual
help) — not primary nav
- Primary content remains scrollable independent of aux pane
*se cases* code editor with linter panel, music player with playlist, document editor with comments, admin form with audit log.
L4 — Custom
When the screen genuinely doesn't fit L1-L3. Examples:
- Full-screen canvas (Koder Calc, Koder Imago)
- Multi-zone dashboards (more than 2 panes that aren't list+detail)
- Single-purpose flows (onboarding, error pages)
*ules*
- Justify in PR review why L1-L3 don't fit
- Document the custom layout's breakpoint behavior in the screen's
README
- Use
KoderApp(safeArea: true)persafe-area.kmd - Avoid horizontal scrolling at Compact
- Consider degrading to L1-L3 on smaller classes
Decision flowchart
Is the content a homogeneous list?
YES → L1 (Feed)
NO ↓
Does the user pick one item to see its details?
YES → L2 (List-detail)
NO ↓
Is there a primary view + a secondary supporting view?
YES → L3 (Supporting pane)
NO → L4 (Custom — justify)Cross-link
adaptive-design.kmd— when layouts switch breakpointswindow-size-classes.kmd— class thresholdssafe-area.kmd— insets at any classnavigation/back-behavior.kmd— back behavior per layout