TanStack Router Nesting Ritual
The standard protocol for fixing 'ghost navigation' issues caused by parent route shadowing.
🧩 TanStack Router Hierarchy Ritual
Version: 1.0 Problem Solved: The URL changes, logs show a successful navigation, but the page content remains unchanged (still showing the parent list view).
1. The Core Issue: The Shadow Block
In TanStack Router, the naming of route files determines the rendering hierarchy:
routes/$lang.blog.tsxis the Parent Layout.routes/$lang.blog.index.tsxis the Default Child Route.routes/$lang.blog.$slug.tsxis the Sibling Child Route.
❌ The Anti-Pattern
If you write the list UI directly in routes/$lang.blog.tsx, when you navigate to $slug:
- The Router matches the child route.
- The Router looks for an
<Outlet />in the parent route to render the child's content. - Because the parent is full of list code and has no
<Outlet />, the child, even though loaded, has "nowhere to sit," making the page appear unresponsive.
2. The Standard Fix Ritual (The Ritual)
To completely resolve this, the "Logic Sinking" protocol must be enforced:
Step 1: Empty the Parent Route (routes/$lang.blog.tsx)
The parent route must act only as a container, holding no specific business UI.
tsximport { createFileRoute, Outlet } from '@tanstack/react-router'; export const Route = createFileRoute('/$lang/blog')({ component: () => <div className="blog-layout"><Outlet /></div>, });
Step 2: Sink the List to the Index (routes/$lang.blog.index.tsx)
Move all list code from the parent route into .index.tsx. This makes the list a "child route" of the parent, mutually exclusive with the detail page.
Step 3: Isolate the Detail Page (routes/$lang.blog.$slug.tsx)
Ensure the detail page uses the $slug dynamic parameter.
3. Physical Unmount Advantage
With this structure:
- When the user is at
/blog, the system rendersLayout -> Index(List). - When the user clicks a detail link, the system renders
Layout -> $slug(Detail). - The Index(List) is physically unmounted, eliminating any possibility of component stacking or shadowing.
4. Troubleshooting Checklist
- Check for Outlet: Is there an
<Outlet />in the parent route file? - Check for Path Conflicts: Is the
addChildreninrouteTree.gen.tsnested correctly? - Check Link Type: Are you using the
toprop and passing the correctparams?
Recorded Jan 2025 - A guide for indie developers to avoid common pitfalls.