Responsive Intelligence

See it work

Pick a width or drag the corner. Watch the sidebar become a drawer, the logo and breadcrumb swap, the cards reflow and the heading shrink. None of it uses a breakpoint class.

Acme
Acme
Overview

Good morning, Jordan

Revenue

1,284

Active users

1,284

Conversion

1,284

Churn

1,284

Four layers

Layer 1

The shell follows its frame

AppFrame measures its own width, not the window's. Below 768px (or 1024px with compactBelow="lg") the one Sidebar slides in as a drawer and SidebarTrigger appears. It behaves the same on a phone, in a narrow window and inside a Studio preview.

Layer 2

Content follows its container

Grid columns="auto" fits as many columns as the space allows, each at least minWidth wide, up to maxColumns. Cards reflow when the sidebar opens, collapses or becomes a drawer, with no breakpoint classes.

Layer 3

Details follow the frame too

shavin-frame-compact-only and shavin-frame-wide-only show or hide a detail (a logo in the top bar, a breadcrumb parent) in step with the drawer. Pure CSS, so nothing flashes on first paint.

Layer 4

Headings scale smoothly

Heading sizes xl and up grow with the nearest container, or the window outside one, between a fixed floor and ceiling. A hero is 72px on a wide page and shrinks in a narrow column or panel on its own.

The shell: AppFrame

Write the navigation once and pass it as sidebar. Put SidebarTrigger in the TopBar; it only shows while the frame is compact. Pass routeKey so the drawer closes after navigation.

<AppFrame routeKey={pathname} sidebar={<Sidebar>…</Sidebar>}>
  <TopBar>
    <SidebarTrigger />
    <Logo className="shavin-frame-compact-only" />
    <Breadcrumbs className="shavin-frame-wide-only" />
  </TopBar>
  <main>…</main>
</AppFrame>

Content: Grid columns="auto"

minWidth sets the narrowest a card may get (xs 10rem, sm 14rem, md 18rem, lg 24rem, xl 32rem); maxColumns stops a row from spreading too wide. Keep fixed columns for splits, spans and timelines.

<Grid columns="auto" minWidth="sm" maxColumns="4" gap="4">
  {stats.map((s) => <StatCard key={s.id} {...s} />)}
</Grid>

Type: fluid Heading sizes

Pick the size for the widest layout. On a phone, in a split column or inside a narrow app frame it scales down on its own. Body and UI text stay fixed for readability, and every size still grows with browser zoom.

SizeRangeTypical use
5xl36–72pxHero
4xl36–60pxDisplay
3xl36–48pxSection title, CTA
2xl30–36pxSection title
xl24–30pxSub-section, card group
lg, md, sm24, 20, 18px (fixed)Card and UI titles

Need one size everywhere? A size class in className replaces the fluid size.

<Heading as="h1" size="5xl">Grows from 36 to 72px</Heading>
<Heading as="h1" size="5xl" className="text-6xl">Always 60px</Heading>

Agent guard

validate_code, audit_source and check_page warn when code goes back to screen-width tricks, so agents keep to the patterns above.

RuleCatches
viewport-sidebarA Sidebar shown or hidden with md:hidden / hidden md:block
drawer-nav-copyA second copy of the navigation inside a Drawer
matchmedia-shellmatchMedia width checks next to a Sidebar
manual-menu-buttonA hand-made menu IconButton instead of SidebarTrigger
viewport-in-framemd:hidden / hidden md:block inside an AppFrame
viewport-heading-sizeHeading sizes stepped with breakpoint size classes such as md:text-5xl

When breakpoints are still right

Screen-width breakpoints stay for whole-page art direction that intrinsic layout cannot express: a hero that swaps its image for a different crop, a section that reorders its columns, a marketing header menu. Tables and list-and-detail layouts do not have an adaptive pattern yet.

Art directionMarketing headersTables (for now)
Configure Theme
Theme
Accent Color
Custom
Gray Family
Appearance
Radius
Scaling
Panel Style
Heading Font
Body Font