All Docs
FeaturesSaaS FactoryUpdated March 10, 2026

Dashboard Responsive Grid Pattern (TPL-M01)

Dashboard Responsive Grid Pattern (TPL-M01)

All dashboard stat-card sections must use a consistent responsive grid layout. This contract ensures:

  1. The loading skeleton and live content share identical grid shapes, preventing cumulative layout shift (CLS) during hydration.
  2. AI agents generating new stat sections always produce correct responsive classes.

Required Grid Classes

Use caseclassName
4-up stat cardsgrid gap-4 sm:grid-cols-2 lg:grid-cols-4
2-up panelsgrid gap-4 sm:grid-cols-2
2-up wide cardsgrid gap-6 lg:grid-cols-2

Example

// Correct ✅ — 4-up stat card row
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
  <StatCard title="MRR" value="$12,400" />
  <StatCard title="Churn" value="2.1%" />
  <StatCard title="Active Users" value="348" />
  <StatCard title="NPS" value="62" />
</div>

// Incorrect ❌ — plain flex row breaks on mobile
<div className="flex flex-row gap-4">
  <StatCard ... />
</div>

// Incorrect ❌ — vertical stack loses the grid benefit
<div className="flex flex-col gap-4">
  <StatCard ... />
</div>

Skeleton Alignment

loading.tsx renders a DashboardSkeleton that uses the identical class strings. If you change the grid class on any live section, update the corresponding skeleton placeholder to match, or users will see a layout jump when content loads.

Nested Components

If a child component (e.g. OverviewStats) already renders its own grid gap-4 sm:grid-cols-2 lg:grid-cols-4 wrapper internally, do not add a second outer grid wrapper at the route level — this creates a double-nested grid that breaks the layout. Add a doc comment at the route level instead, as done for <OverviewStats /> in dashboard/page.tsx.

Where the Contract Lives

The canonical reference comment appears at the top of both:

  • src/app/dashboard/page.tsx — live application
  • template/src/app/dashboard/page.tsx — product template

Any AI agent or engineer adding a new stat section to the dashboard should read that comment before generating grid markup.