Layout — Window size classes

mandatory

4 canonical window-size classes (Compact / Medium / Expanded / Large) that Koder UIs adapt to. Defines breakpoints in dp, detection per surface (Flutter, Web, native Android), and the expected layout responses at each class. Material parity (`/foundations/layout/applying-layout/window-size-classes`).

Spec — Window size classes

Facet *isual*do Koder Design. Material parity: https://m3.material.io/foundations/layout/applying-layout/window-size-classes.

The 4 classes

Class Width (dp) Typical surfaces Columns (grid)
*ompact* 0–599 Phone portrait, watch 4
*edium* 600–839 Phone landscape, small tablet, foldable inner 8
*xpanded* 840–1199 Large tablet, small laptop, foldable outer 12
*arge* ≥ 1200 Desktop, ultrawide, TV 12+

Breakpoints are in *ensity-independent pixels (dp)*so Flutter, Web, and Android share the mental model. Web converts to CSS px 1:1 below high-DPI; above HDPI it follows window.devicePixelRatio.

R1 — Detect class per surface

Flutter

WindowSizeClass classOf(BuildContext context) {
  final w = MediaQuery.of(context).size.width;
  if (w < 600)  return WindowSizeClass.compact;
  if (w < 840)  return WindowSizeClass.medium;
  if (w < 1200) return WindowSizeClass.expanded;
  return WindowSizeClass.large;
}

koder_kit exposes KoderWindowClass.of(context) (planned).

Web

:root {
  --wc-compact:  599px;
  --wc-medium:   839px;
  --wc-expanded: 1199px;
}

@media (max-width: 599px)  {  }
@media (min-width: 600px) and (max-width: 839px)  {  }
@media (min-width: 840px) and (max-width: 1199px) {  }
@media (min-width: 1200px) {  }

koder_web_kit exposes data-window-class="compact|medium|..." attribute on <html> (planned).

Native Android

WindowSizeClass from Jetpack androidx.window.core.layout (Android 12+). Mapping is 1:1 with the above thresholds.

CLI / TUI

TTY columns (terminfo). Adapt at:

  • Compact: < 80 cols → single column, abbreviate labels
  • Medium: 80–119 cols → 2 columns, full labels
  • Expanded: 120–159 cols → 3 columns, descriptions
  • Large: ≥ 160 cols → full table layouts, side panes

R2 — Layout response per class

What changes at each class (canonical):

Element Compact Medium Expanded Large
Navigation Bottom bar Bottom bar Nav rail Nav drawer (persistent)
Container padding 16dp 16dp 24dp 32dp
Card/grid columns 1 2 3 4+
List density Comfortable Comfortable Comfortable Compact (optional)
Dialog Full-screen sheet Full-screen Centered modal Centered modal
Date picker Calendar full-screen Calendar full-screen Inline + popup Inline + popup
Search Full-width bar in app bar Bar in app bar Inline search field Inline + always-visible

R3 — Multiwindow / splitscreen

Foldables and desktops support split-screen. Koder UIs:

  • Listen for class changes (MediaQuery rebuild, ResizeObserver)
  • Pick canonical layout fresh per class change
  • Preserve state across transitions (scroll, form input, selection)

Antipattern: hardcoding "isPhone" — use class detection so the same code works on tablet split-screen Compact.

R4 — Orientation independence

Window class is determined by *idth* not orientation. A landscape phone is Medium, not Compact. Avoid Orientation queries except for truly orientation-sensitive UI (camera viewfinder, AR).

R5 — Type scale

Type scale adjusts per class:

Class Display Headline Body
Compact -1 step -1 step base
Medium base base base
Expanded +1 step base base
Large +1 step +1 step base

(Concrete sizes in future typography.kmd.)

R6 — Forbidden patterns

  • ❌ Single hardcoded breakpoint (if width < 768) without class taxonomy
  • ❌ Orientation-only checks (portrait vs landscape)
  • ❌ Different code paths for "mobile" vs "desktop" with no class
  • ❌ Pixel hardcoding (width: 320px); use dp + class
  • adaptive-design.kmd — strategies (resizereflowtransform)
  • canonical-layouts.kmd — 4 layouts per class behavior
  • safe-area.kmd — insets at every class

Source: ../home/koder/dev/koder/meta/docs/stack/specs/app-layout/window-size-classes.kmd