#Layout Changing Based on Route
1 messages · Page 1 of 1 (latest)
Hi @young patrol. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
Layouts in the App Router don’t receive the current pathname or search params and they don’t re‑render on navigation, so you can’t just “pass the route” into a shared layout on the server. [Layout caveats]
Depending on what you want to change, the recommended options are:
1. Use nested layouts (server‑side, path‑based)
If the differences in layout are tied to specific path segments, create additional layouts in those folders. Each segment’s layout.tsx wraps its children, so the layout naturally changes with the route. [Nesting layouts]
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
return <html><body>{children}</body></html>
}
// app/blog/layout.tsx – only for /blog and its children
export default function BlogLayout({ children }: { children: React.ReactNode }) {
return <section className="blog-shell">{children}</section>
}
You can also use route groups (e.g. (marketing), (shop)) to organize or branch layouts without affecting the URL. [Project structure examples; Root layout reference]
2. Use dynamic route params in layouts (server‑side)
If the path differences are in dynamic segments, you can read params directly in the layout and branch on them. [Dynamic routes; Layout params]
// app/dashboard/[team]/layout.tsx
export default async function DashboardLayout({
children,
params,
}: {
children: React.ReactNode
params: Promise<{ team: string }>
}) {
const { team } = await params
const themeClass = team === 'design' ? 'design-theme' : 'default-theme'
return (
<section className={themeClass}>
<header>Welcome to {team}'s dashboard</header>
<main>{children}</main>
</section>
)
}
This keeps everything server‑side and layout will vary based on the URL’s dynamic part.
3. For finer routing info (segment, pathname) use a small client wrapper
If you need to react to the exact current segment or pathname (including changes on client‑side transitions), the docs recommend a tiny Client Component inside the layout using:
useSelectedLayoutSegment(s)to see which child segment is active, orusePathnameto read the full path. [Accessing child segments; Layout caveats – pathname]
Example:
// app/ui/nav-shell.tsx
'use client'
import { usePathname } from 'next/navigation'
export function NavShell({ children }: { children: React.ReactNode }) {
const pathname = usePathname()
const compactHeader = pathname.startsWith('/dashboard')
return (
<div className={compactHeader ? 'compact' : 'full'}>
{children}
</div>
)
}
// app/layout.tsx
import { NavShell } from '@/app/ui/nav-shell'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<NavShell>{children}</NavShell>
</body>
</html>
)
}
Here the layout is still a Server Component; only the minimal piece that depends on live routing is client‑side as recommended. [Layout examples – active nav links]
So, for a “layout that changes slightly based on the route” and remains server‑driven:
- Prefer nested layouts and route groups for structural differences.
- Use
paramsin layouts when the variation depends on dynamic segments. - Only if you need live URL awareness across navigations, add a small Client Component inside the layout to read the current segment/path.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@young patrol Kapa.ai is still learning and improving, please let me know how I did by reacting below.
In your nested layout example, if you have a footer that you want to show in the root layout, but not in the blog layout, how would you do that? @thorny coral
Let me check the knowledge base for you again. Give me one moment! :books:
You’d structure the layouts so the footer is only rendered by the root layout, and the blog layout doesn’t include it.
In the App Router, layouts are nested: app/layout.tsx wraps app/blog/layout.tsx, which then wraps app/blog/page.tsx and app/blog/[slug]/page.tsx. [Nesting layouts]
// app/layout.tsx – root layout, used for all routes
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
{/* Header / nav */}
<header>Global header</header>
{/* Everything under /, including /blog, is rendered here */}
<main>{children}</main>
{/* Footer shown on all routes, including /blog */}
<footer>Global footer</footer>
</body>
</html>
)
}
// app/blog/layout.tsx – blog-specific layout, *no* footer here
export default function BlogLayout({
children,
}: {
children: React.ReactNode
}) {
// Only blog-specific chrome; footer is not repeated here
return <section className="blog-shell">{children}</section>
}
With this structure:
/aboutrenders:RootLayout→AboutPage(footer visible)./blogrenders:RootLayout→BlogLayout→BlogIndexPage(same footer, but no extra footer from the blog layout). [Layouts and pages; Nesting layouts]
If you wanted the footer on most routes but not under /blog, you’d need a different layout branch (e.g. via route groups) so /blog uses a root layout without the footer while other groups use one with the footer. The docs describe using route groups to create multiple root layouts for different sections. [Route groups; Project structure examples]
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@young patrol Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@thorny coral Yes, I want the footer on most routes but not under /blog
Let me check the knowledge base for you again. Give me one moment! :books:
To have a footer on most routes but not under /blog, use route groups with multiple root layouts:
- Remove the single top-level
app/layout.tsx. - Create two route groups, each with its own root layout:
(marketing)(or any name) – with footer, for most routes.(blog)– without footer, for/blogand its children.
The folders inside () don’t affect the URL, but each can define its own root layout.tsx. [Route groups; Creating multiple root layouts]
Example structure:
app
/(marketing)
layout.tsx // has footer
page.tsx // '/'
about/page.tsx // '/about'
/(blog)
layout.tsx // no footer
blog/page.tsx // '/blog'
blog/[slug]/page.tsx
app/(marketing)/layout.tsx (with footer):
export default function MarketingLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<header>Global header</header>
<main>{children}</main>
<footer>Global footer</footer>
</body>
</html>
)
}
app/(blog)/layout.tsx (no footer):
export default function BlogRootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<header>Blog header</header>
<main>{children}</main>
{/* No footer here */}
</body>
</html>
)
}
Notes:
- The home route
/must live under one of the groups (e.g.app/(marketing)/page.tsx). [Route groups caveats] - Navigating between routes that use different root layouts (e.g.
/about→/blog) causes a full page load, which is expected. [Route groups caveats; Root layout reference]
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@young patrol Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Really, what would be nice for me is to have the home page specifically be a different layout than every other page. Is there a simple way to do that? @thorny coral
Let me check the knowledge base for you again. Give me one moment! :books:
Yes. The simplest App Router way is to give / its own root layout using route groups and multiple root layouts. [Route groups; Project structure examples]
Folder structure
app
/(home)
layout.tsx // layout used only for "/"
page.tsx // home route "/"
/(main)
layout.tsx // layout used for every other route
about
page.tsx // "/about"
blog
page.tsx // "/blog"
The folder names in parentheses don’t appear in the URL.
Example layouts
app/(home)/layout.tsx – special home-page layout
export default function HomeLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body className="home-layout">
{/* Home-only hero, no global nav, different footer, etc. */}
{children}
</body>
</html>
)
}
app/(main)/layout.tsx – default layout for all other routes
export default function MainLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body className="main-layout">
<header>Site header</header>
<main>{children}</main>
<footer>Global footer</footer>
</body>
</html>
)
}
Caveats:
- You must not have a top-level
app/layout.tsxwhen using multiple root layouts like this. [Project structure examples] - Navigating between different root layouts (e.g.
/→/about) triggers a full page load. [Route groups]