T
TanStack9mo ago
foreign-sapphire

Nested layouts work in flat but not directory based syntax

so i have routes like this that work fine:
src/
├── routes/
├── _auth-layout/
├── index.tsx
├── settings.organization.tsx
├── settings.panels.tsx
├── settings.tsx
├── __root.tsx
├── _auth-layout.tsx
src/
├── routes/
├── _auth-layout/
├── index.tsx
├── settings.organization.tsx
├── settings.panels.tsx
├── settings.tsx
├── __root.tsx
├── _auth-layout.tsx
but if I try and do it in a directory based style it breaks -- specifically the outlet on the tabs doesn't render the child routes
src/
├── routes/
├── _auth-layout/
├── settings/
├── organization.tsx
├── panels.tsx
├── index.tsx
├── index.tsx
├── __root.tsx
├── _auth-layout.tsx
src/
├── routes/
├── _auth-layout/
├── settings/
├── organization.tsx
├── panels.tsx
├── index.tsx
├── index.tsx
├── __root.tsx
├── _auth-layout.tsx
5 Replies
foreign-sapphire
foreign-sapphireOP9mo ago
import { cn } from "@/lib/utils";
import {
Link,
Outlet,
createFileRoute,
linkOptions,
redirect,
useRouterState,
} from "@tanstack/react-router";

export const Route = createFileRoute("/_auth-layout/settings")({
component: RouteComponent,
beforeLoad({ location }) {
if (location.pathname === "/settings") {
throw redirect({
replace: true,
to: "/settings/organizations",
});
}
},
});

const options = [
linkOptions({
to: "/settings/organizations",
label: "Organizations",
helmet: "Organization Settings",
false: true,
}),
linkOptions({
to: "/settings/panels",
label: "Panels",
helmet: "Panel Settings",
disabled: true,
}),
];

function RouteComponent() {
return (
<>
<h1 className="text-4xl font-bold tracking-tight scroll-m-20">
Settings
</h1>

<div className="pt-4">
<AnimatedTabLinks tabs={options} />
</div>
<div className="pt-2" />
</>
);
}

function AnimatedTabLinks({
tabs,
}: {
tabs: { to: string; label: string; disabled: boolean }[];
}) {
const routerState = useRouterState();

return (
<>
<div className="flex space-x-1">
{tabs.map((option) => (
<Link
key={option.to}
disabled={option.disabled}
to={option.to}
>
<span>{option.label}</span>
{routerState.location.pathname === option.to && (
<motion.div
layoutId="active-underline"
/>
)}
</Link>
))}
</div>

<div className="-mt-px border-b border-slate-200" />
<Outlet />
</>
);
}
import { cn } from "@/lib/utils";
import {
Link,
Outlet,
createFileRoute,
linkOptions,
redirect,
useRouterState,
} from "@tanstack/react-router";

export const Route = createFileRoute("/_auth-layout/settings")({
component: RouteComponent,
beforeLoad({ location }) {
if (location.pathname === "/settings") {
throw redirect({
replace: true,
to: "/settings/organizations",
});
}
},
});

const options = [
linkOptions({
to: "/settings/organizations",
label: "Organizations",
helmet: "Organization Settings",
false: true,
}),
linkOptions({
to: "/settings/panels",
label: "Panels",
helmet: "Panel Settings",
disabled: true,
}),
];

function RouteComponent() {
return (
<>
<h1 className="text-4xl font-bold tracking-tight scroll-m-20">
Settings
</h1>

<div className="pt-4">
<AnimatedTabLinks tabs={options} />
</div>
<div className="pt-2" />
</>
);
}

function AnimatedTabLinks({
tabs,
}: {
tabs: { to: string; label: string; disabled: boolean }[];
}) {
const routerState = useRouterState();

return (
<>
<div className="flex space-x-1">
{tabs.map((option) => (
<Link
key={option.to}
disabled={option.disabled}
to={option.to}
>
<span>{option.label}</span>
{routerState.location.pathname === option.to && (
<motion.div
layoutId="active-underline"
/>
)}
</Link>
))}
</div>

<div className="-mt-px border-b border-slate-200" />
<Outlet />
</>
);
}
adverse-sapphire
adverse-sapphire9mo ago
your route component needs to render an <Outlet/>
foreign-sapphire
foreign-sapphireOP9mo ago
<AnimatedTabLinks tabs={options} /> has an Outlet note that this setup works totally fine with the existing setup when using flat structure, but it doesn't when using directory based
adverse-sapphire
adverse-sapphire9mo ago
please provide a complete example by forking one of the existing stackblitz examples
foreign-sapphire
foreign-sapphireOP9mo ago

Did you find this page helpful?