Responsive
Decide what each region does as width changes: divide, reveal, resize, or swap.Breakpoints
Decide what each region does as width changes. Write the responsive contract down for every region before you call the layout done.
| Guidance | Practices |
|---|---|
| Do | Write the contract down for every region before you call the layout done |
| Do | Decide per region whether it is revealed, resized, or swapped at each width |
| Do | Drop a region rather than let it compete for width it does not have |
| Don't | Hold three regions at a width where none of them has usable space |
| Don't | Shrink every region uniformly instead of swapping or dropping one |
| Don't | Wire a breakpoint in CSS that the contract comment never mentions |
Responsive contract
Lock what each region does as width changes, and pair every line of the contract with the prop or hook that enforces it.
- Divide: how many regions survive at each width
- Reveal: which regions earn their width only when there is room, and open on demand below that
- Resize: content flexes while fixed regions hold their budgets, and text stays capped by contentWidth so line length holds
- Swap: navigation becomes
MobileNavat theAppShellmobileNav breakpoint; the side panel becomes aDialogorBottomSheet, driven byuseMediaQuery
tsx// Recommended thresholds: 3 regions above 1024, 2 from 768,// 1 below. Text reads best at 40–60 characters per line.// >1024 SideNav 256 | content | side panel 380// <=1024 panel moves to a Dialog (useMediaQuery)// <=768 nav collapses to MobileNav (mobileNav "md")const isNarrow = useMediaQuery('(max-width: 1024px)');<AppShell sideNav={<SideNav />} mobileNav={{breakpoint: 'md'}}><Layoutcontent={<LayoutContent>{/* rows */}</LayoutContent>}end={isNarrow ? undefined : <LayoutPanel width={380} hasDivider />}/></AppShell>
Verify: every contract line names a mechanism, so the comment cannot drift from the behavior.