Custom Layout for Specific Route Group in Tanstack Router – Solution



This content originally appeared on DEV Community and was authored by حذيفة

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.

Image 1 Image 2 Image 3

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.


This content originally appeared on DEV Community and was authored by حذيفة