Phuriwaj

Mantine AppShell Layout — Debugging Blank Column

A systematic checklist for diagnosing and fixing unexpected blank space on the left side of a Mantine AppShell layout.

Why / When to Use

When a blank white column appears between the icon rail and page content. Usually caused by AppShell reserving navbar space that doesn’t match actual rendered content.

Core Concept / Commands

Diagnostic — count root AppShell instances

grep -rn "AppShell" src --include="*.tsx" | grep -v "AppShell\."

Only ONE root <AppShell> should exist. Multiple instances create stacked reserved space.

Diagnostic — find hardcoded left offsets

grep -rn "marginLeft\|paddingLeft\|margin-left\|padding-left" \
  src/app src/components --include="*.tsx" --include="*.css" --include="*.module.css"

Key Options / Variants

Cause A — Navbar reserved but empty or missing

<AppShell navbar={{ width: N }}> reserves N pixels but <AppShell.Navbar> is not rendered or is empty.

Fix: remove the navbar prop, or render content inside <AppShell.Navbar>, or set navbar={{ width: 0, breakpoint: 'sm' }}.

Cause B — Double AppShell stacking

Root layout AND a route-group layout both declare <AppShell>. Both reserve space, causing combined blank offset.

Fix: remove the inner AppShell. Page-level sidebars belong inside AppShell.Main as a flex row:

<Group h="100%" gap={0} align="stretch">
  <NavSidebar />
  <Box flex={1}>{children}</Box>
  {selectedItem && <DetailPanel />}
</Group>

Cause C — Icon rail outside AppShell + AppShell also has navbar prop

Icon rail sits as a sibling outside <AppShell> while AppShell also has navbar={{ width: N }} — double left offset.

Option 1 — Move icon rail inside AppShell:

<AppShell navbar={{ width: 52, breakpoint: 'sm' }}>
  <AppShell.Navbar withBorder={false}>
    <IconRail />
  </AppShell.Navbar>
  ...
</AppShell>

Option 2 — Keep icon rail outside, remove navbar from AppShell:

<Group h="100vh" gap={0} align="stretch">
  <IconRail />  {/* 52px, flex-shrink: 0 */}
  <AppShell /* NO navbar prop */>
    ...
  </AppShell>
</Group>

Cause D — Hardcoded CSS offset

A global wrapper has marginLeft or paddingLeft compensating for something. Remove it and fix the root cause.

Cause E — Navbar width mismatch

navbar={{ width: N }} doesn’t match the actual rendered sidebar width. Set N to exactly match.

Gotchas

  • The icon rail is typically 52px; set navbar={{ width: 52 }} to match exactly.
  • Always run npx tsc --noEmit after layout changes to catch type errors.
  • Route group layouts ((group)/layout.tsx) are easy to miss when auditing AppShell instances.

Source

Conversation “Web-Todo App” — 2026-05-31