Frontend Layout Tree

Layout architecture for the React 19 web application including scroll ownership, routing, and viewport handling

Overview

The MQUAD frontend uses a single vertical scroll ownership architecture. Each page type has exactly one scroll container to prevent nested scrolling conflicts and ensure predictable behavior across zoom levels and display scaling.

Root Entry Point

src/main.tsx
  └── src/App.tsx
        └── Routes (react-router)
              ├── Public Routes
              │     └── DefaultLayout
              │           └── <Outlet />
              └── Protected Routes
                    └── DashboardLayout  ← PRIMARY SCROLL OWNER
                          └── <Outlet /> (all dashboard pages)

Layout Structure

Default Layout (Public Pages)

// File: src/components/layouts/default-layout.tsx
<div className="flex flex-col min-h-screen bg-primary-foreground">
  <header className="p-4 bg-secondary border-b">
  <main id="main-content" className="flex-1">  ← No scroll owner
  <Footer />
</div>
  • Used for: Login, Landing pages, Public content
  • Scroll behavior: Inherits from viewport (no internal scrolling)
  • Key pattern: min-h-screen (not h-screen) for safe scaling

Dashboard Layout (Protected Pages)

// File: src/components/layouts/dashboard-layout.tsx
<SidebarProvider>  ← Uses min-h-svh internally
  <DashboardSidebar />
  <main className="sm:w-full flex flex-col">  ← Row container only
    <div className="flex flex-col w-full z-50">  ← Header bar (sticky)
      <SidebarTrigger />
      <DarkMode />
    </div>
    <section className="w-full flex-1 flex flex-col min-h-0 overflow-auto">  ← PRIMARY SCROLL OWNER
      <Banner />
      <div className="flex-1 flex-col min-h-0">  ← Inner flex container
        <header className="flex items-center p-2 mx-5">
        <section className="pt-10 flex-1">
          <div className="p-2">
            <Outlet />  ← All dashboard pages render here
          </div>
        </section>
      </div>
      <SimpleFooter />
    </section>
  </main>
</SidebarProvider>
ElementClassesRoleScroll Ownership
SidebarProvider-Sidebar contextNone (w/ min-h-svh)
mainsm:w-full flex flex-colRow containerNone
div.z-50flex flex-col w-fullSticky headerNone
section (line 154)w-full flex-1 flex flex-col min-h-0 overflow-autoContent areaOWNER
div (line 156)flex-1 flex-col min-h-0Inner wrapperNone (supports parent)

Scroll Ownership Rules

  1. One scroll owner per page type — Only section at line 154 has overflow-auto
  2. Inner containers need min-h-0 — Allows flex scrolling to propagate
  3. Loading states use min-h-screen — Safer than h-screen at Windows scaling >100%
  4. Dialog/Sheet content are independent — They have their own scroll containers (do not modify)

Contained Scroll Areas

These components use overflow-auto with explicit height constraints — NOT page-level scroll owners:

ComponentFilePattern
ScrollAreasrc/components/ui/scroll-area.tsxRadix UI scroll area
DialogContentVarious dialog filesmax-h-[80vh] overflow-y-auto
SheetContentVarious sheet filesoverflow-y-auto
Response tablessrc/components/shared/advance-table.tsxVirtualized scrolling

Key Files

FilePurpose
src/components/layouts/dashboard-layout.tsxPrimary scroll owner for dashboard
src/components/layouts/default-layout.tsxPublic pages layout
src/components/layouts/dashboard-sidebar-layout.tsxSidebar navigation
src/components/ui/sidebar.tsxSidebar component (uses min-h-svh)

Testing Scroll Behavior

Test at these settings to verify proper scroll behavior:

Platform SettingExpected Behavior
Windows scaling: 100%Scroll works normally
Windows scaling: 125%Scroll area calculates correctly
Windows scaling: 150%Content not clipped
Windows scaling: 175%Full content accessible
Browser zoom: 80%Scroll boundary correct
Browser zoom: 200%Scroll wheel works smoothly

Common Issues & Fixes

IssueCauseFix
Content clipped at 125% scalingh-screen is smaller than scaled viewportUse min-h-screen
Nested scrollbarsMultiple elements with overflow-autoRemove duplicate scroll owners
Scroll not workingMissing min-h-0 on flex childrenAdd min-h-0 to support flex scrolling