if you read this issue discussion on GitHub :
Custom Layout for Specific Routes in tanstack/router #1102
you’ll see that this is a big issue. Surprisingly, such a basic feature is not available in a large project like TanStack Router. Even though the issue is marked as resolved, that’s not really the case. I tried all the suggested solutions, but none of them worked for me. I also went through the documentation and found that there’s still no official support for this. However, I managed to solve it with a workaround.
![]() |
![]() |
|---|
The Scenario :
I am working on a [react + vite + Tanstack Router] Project for a clothes store,
I have two type of pages :
- regular pages : Home Page, Product Page, Collection Page, Search Page, Checkout Page.
- Dashboard Pages : Statistics Page, CRUD Product Page, Handling Orders Page,
The regular pages anyone can navigate them, and they have layout of <NavBar /> & <Footer />
The Dashboard pages for the admin, and they have layout of <SideBar />
The routing type implemented here is the File-Based Routing.
The Problem :
when I set a custom layout for the dashboard, it wrapped by the layout of the regular pages.
The /src/routes directory Hierarchy :
\routes
| checkout.jsx
| collection.jsx
| index.jsx
| product.jsx
| search.jsx
| __root.jsx
|
\---dashboard
| index.jsx
| route.jsx
|
\---products
index.jsx
the src/routes/__root.jsx file :
import { createRootRoute, Outlet } from "@tanstack/react-router";
import Navbar from "@/components/Navbar";
import Footer from "@/components/Footer";
import NotFoundPage from "@/components/NotFoundPage";
export const Route = createRootRoute({
notFoundComponent: () => <NotFoundPage />,
component: () => {
return (
<div>
<Navbar />
<Outlet />
<Footer />
</div>
);
},
});
the /src/routes/dashboard/route.jsx file :
import { Outlet, Link, createFileRoute } from "@tanstack/react-router";
import SideBar from "@/componenets/SideBar";
export const Route = createFileRoute("/dashboard")({
component: () => {
return (
<div className="flex h-screen bg-gray-50">
<SideBar />
<main className="flex-1 p-6 overflow-y-auto">
<Outlet />
</main>
</div>
);
},
});
so when i browse /Dashboard/products
The Given Result :
<NavBar />
<div className="flex h-screen bg-gray-50">
<SideBar />
<main className="flex-1 p-6 overflow-y-auto">
<Outlet />
</main>
</div>
<Footer/>
The Wanted Result :
<div className="flex h-screen bg-gray-50">
<SideBar />
<main className="flex-1 p-6 overflow-y-auto">
<Outlet />
</main>
</div>
So How can you set a custom Layout for Dashboard Sub Pages.
The Solution :
The trick is to use conditional rendering: if the route starts with /dashboard/, it won’t be wrapped by any component.
the src/routes/__root.jsx file again, but with Conditional Rendering :
import React, { useState} from "react";
import { createRootRoute, Outlet, useLocation } from "@tanstack/react-router";
import Navbar from "../components/Navbar";
import Footer from "../components/Footer";
import NotFoundPage from "../components/NotFoundPage";
export const Route = createRootRoute({
notFoundComponent: () => <NotFoundPage />,
component: RootComponent,
});
function RootComponent() {
const location = useLocation();
const pathname = location.pathname;
if (pathname.startsWith("/dashboard")) {
return <DashboardRoute />;
} else {
return <RegularRoute />;
}
}
function DashboardRoute() {
return (
<>
<Outlet />
</>
);
}
function RegularRoute() {
return (
<Navbar />
<Outlet />
<Footer />
);
}
I hope this is helpful to everyone.
leave a love & a comment so more people can reach it.


Top comments (7)
Here is a complete solution that achieves multiple root routes while leveraging the efficient partial route rendering.
This solution uses pathless routes for both route groups.
These are the keys.
routes/index.tsxand createroutes/_regular/index.tsx.__root.tsxto_regular/route.tsx.Note that
routes/index.tsxandroutes/_regular/index.tsxcannot exist at the same time.I saw like this solution in the issue discussion before, it didn't work to me, or may be I didn't understand it well, it was confusing.
and about pathless layout, I read about it before in the official documentation and it didn't work also.
Anyway !
When I looked at your solution, I realized I had been overcomplicating things. I tried your approach in my project, and it worked well—at least until I ran into the following error:
The issue was that
__root.jsxis still a crucial file. It’s required by the@tanstack/router-plugin/viteplugin to generate therouteTree.gen.tsfile, which is then imported and initialized in the app’s entry point (/src/main.jsxin my case).Here’s my
/src/main.jsx:/src/main.jsx:So, your solution works perfectly, but it just needs this small additional file:
/src/routes/__root.jsxThank you so much, I appreciate your help.
Yeah I forgot the __root.tsx sorry. It is required.
Thanks mate. Been stuck on this for hours. You're a legend.
Thanks for sharing the idea.
However, the problem is, since the root component is using the hook
useLocation(), whenever the route changes, the whole application is re-rendered.Your solution follows the official guidelines and represents best practices. In contrast, my approach was more of a workaround. Your implementation is clean and maintainable, whereas mine turned into spaghetti code. Clearly, your approach is the better one.
@jhaemin
may be the cover image should be like this :