#Layout Changing Based on Route

1 messages · Page 1 of 1 (latest)

young patrol
#

I want my layout to change slightly based on the url path route. What's the best way to do this while having everything be server side? It would be nice if I could pass a prop in saying the route or something

thorny coralBOT
#

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:

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 params in 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.

young patrol
#

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

thorny coralBOT
#

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:

  • /about renders: RootLayoutAboutPage (footer visible).
  • /blog renders: RootLayoutBlogLayoutBlogIndexPage (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.

young patrol
#

@thorny coral Yes, I want the footer on most routes but not under /blog

thorny coralBOT
#

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:

  1. Remove the single top-level app/layout.tsx.
  2. Create two route groups, each with its own root layout:
  • (marketing) (or any name) – with footer, for most routes.
  • (blog) – without footer, for /blog and 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:

#

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.

young patrol
#

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

thorny coralBOT
#

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.tsx when using multiple root layouts like this. [Project structure examples]
  • Navigating between different root layouts (e.g. //about) triggers a full page load. [Route groups]

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: