Falytom logoFALYTOM
Games
ToolsUI ComponentsServicesProductsAbout
menu
  1. Home
  2. /Web Development
  3. /Nextjs
  4. /Understanding Layouts
Your Progress0%
0 of 70 completed

NextJS Topics

Getting Started

  • What is Next.js?
  • Next.js vs React - Key Differences
  • Creating Your First Next.js 15 Project
  • Next.js Project Structure Explained
  • App Router vs Pages Router

Routing Fundamentals

  • File-Based Routing Basics
  • Creating Pages with page.tsx
  • Dynamic Routes and Route Parameters
  • Catch-All and Optional Catch-All Routes
  • Route Groups for Organization
  • Parallel Routes
  • Intercepting Routes

Layouts and Pages

  • Understanding Layouts
  • Root Layout and Global Configuration
  • Nested Layouts
  • Templates vs Layouts
  • Loading States with loading.tsx
  • Error Handling with error.tsx

Server and Client Components

  • Understanding Server Components
  • Client Components with 'use client'
  • When to Use Server vs Client Components
  • Component Composition Patterns
  • Passing Props Between Server and Client
  • Server Component Patterns and Best Practices

Data Fetching

  • Fetching Data in Server Components
  • Parallel and Sequential Data Fetching
  • Data Fetching Patterns and Strategies
  • Caching and Revalidation
  • Revalidate and Cache Tags
  • Handling Loading and Error States in Data Fetching

Navigation and Links

  • Link Component Basics
  • useRouter Hook for Programmatic Navigation
  • usePathname and useSearchParams Hooks
  • Active Links and Navigation States
  • Redirects and Navigation Guards

Styling in Next.js

  • CSS Modules in Next.js
  • Tailwind CSS Setup and Configuration
  • Global Styles and CSS Variables
  • Next.js Font Optimization

Images and Media

  • Next.js Image Component Basics
  • Image Optimization and Best Practices
  • Working with Static Assets

Forms and Data Mutations

  • Understanding Server Actions
  • Form Handling with Server Actions
  • Form Validation and Error Handling
  • useFormStatus and useFormState Hooks
  • Revalidating Data After Mutations
  • Optimistic Updates

Metadata and SEO

  • Static Metadata Configuration
  • Dynamic Metadata Generation
  • Open Graph and Social Media Cards
  • Sitemap and Robots.txt

API Routes and Route Handlers

  • Route Handlers Introduction
  • GET and POST Request Handlers
  • Dynamic API Routes
  • Request and Response Objects
  • API Error Handling and Status Codes

Middleware and Advanced Features

  • Introduction to Middleware
  • Authentication with Middleware
  • Environment Variables and Configuration
  • Streaming and Suspense
  • Not Found and Global Error Pages

Deployment and Optimization

  • Understanding Static and Dynamic Rendering
  • generateStaticParams for Static Generation
  • Build and Production Optimization
  • Deploying to Vercel
  • Alternative Deployment Options
  • Performance Monitoring and Analytics

Real-World Projects

  • Project 1: E-commerce Product Catalog
  • Project 2: Dashboard with Authentication

Understanding Layouts

Creating shared UI that persists across multiple pages

Most websites have UI that appears on multiple pages—navigation bars, footers, sidebars. Without layouts, you'd duplicate this code in every page, making maintenance a nightmare. Layouts solve this by letting you create shared UI once and wrap multiple pages with it. Even better, layouts persist across navigation, meaning they don't re-render when users move between pages. This keeps state intact and improves performance. Let's master this fundamental Next.js concept!

What Are Layouts?

A layout is a UI component that wraps one or more pages. It's defined in a layout.tsx file and uses React's children prop to render page content inside it.

The Problem Without Layouts

Without layouts, you'd repeat code in every page:

app/page.tsx
export default function HomePage() {
  return (
    <>
      <header>
        <nav>{/* Navigation */}</nav>
      </header>
      
      <main>
        {/* Homepage content */}
      </main>
      
      <footer>{/* Footer */}</footer>
    </>
  );
}
app/about/page.tsx
export default function AboutPage() {
  return (
    <>
      <header>
        <nav>{/* Same navigation - duplicated! */}</nav>
      </header>
      
      <main>
        {/* About content */}
      </main>
      
      <footer>{/* Same footer - duplicated! */}</footer>
    </>
  );
}

Problems with this approach:

  • Code duplication everywhere
  • Hard to maintain - change one, change all
  • Header/footer re-render on every navigation
  • State doesn't persist (like open menus)

The Solution: Layouts

With layouts, you define shared UI once:

app/layout.tsx
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <>
      <header>
        <nav>{/* Navigation - defined once! */}</nav>
      </header>
      
      <main>{children}</main>
      
      <footer>{/* Footer - defined once! */}</footer>
    </>
  );
}

Now your pages are just the unique content:

app/page.tsx
export default function HomePage() {
  return <div>{/* Just homepage content */}</div>;
}
app/about/page.tsx
export default function AboutPage() {
  return <div>{/* Just about content */}</div>;
}

Benefits of Layouts

  • No duplication: Write shared UI once
  • Easy maintenance: Change in one place
  • Persistent UI: Layouts don't re-render on navigation
  • State preservation: Layout state persists between pages

Creating Your First Layout

Let's create a simple layout with a header and footer:

Step 1: Create layout.tsx

app/layout.tsx
import Link from 'next/link';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        {/* Header - shows on all pages */}
        <header className="bg-blue-600 text-white">
          <nav className="container mx-auto px-4 py-4">
            <div className="flex items-center justify-between">
              <div className="text-xl font-bold">My App</div>
              <div className="flex gap-6">
                <Link href="/" className="hover:underline">
                  Home
                </Link>
                <Link href="/about" className="hover:underline">
                  About
                </Link>
                <Link href="/blog" className="hover:underline">
                  Blog
                </Link>
                <Link href="/contact" className="hover:underline">
                  Contact
                </Link>
              </div>
            </div>
          </nav>
        </header>

        {/* Page content renders here */}
        <main className="min-h-screen">
          {children}
        </main>

        {/* Footer - shows on all pages */}
        <footer className="bg-gray-800 text-white py-8">
          <div className="container mx-auto px-4 text-center">
            <p>© 2024 My App. All rights reserved.</p>
          </div>
        </footer>
      </body>
    </html>
  );
}

Step 2: Create Pages

Pages automatically get wrapped by the layout:

app/page.tsx
export default function HomePage() {
  return (
    <div className="container mx-auto px-4 py-8">
      <h1 className="text-4xl font-bold mb-4">Welcome Home</h1>
      <p className="text-lg">This page is wrapped by the layout!</p>
    </div>
  );
}
app/about/page.tsx
export default function AboutPage() {
  return (
    <div className="container mx-auto px-4 py-8">
      <h1 className="text-4xl font-bold mb-4">About Us</h1>
      <p className="text-lg">This page also uses the same layout!</p>
    </div>
  );
}

✨ Automatic Wrapping

You don't need to import or reference the layout. Next.js automatically wraps pages with layouts in their route segment. It just works!

How Layouts Work

The children Prop

Layouts receive a children prop that contains the page content:

TYPESCRIPT
export default function Layout({
  children,    // This is the page content
}: {
  children: React.ReactNode;
}) {
  return (
    <div>
      <header>Header</header>
      {children}  {/* Page renders here */}
      <footer>Footer</footer>
    </div>
  );
}

Layout Hierarchy

When you visit a page, Next.js:

  1. Finds all layouts in the route path
  2. Nests them from root to leaf
  3. Renders the page as the innermost child
PLAINTEXT
URL: /blog/my-post

Rendering hierarchy:
app/layout.tsx
  └─ app/blog/layout.tsx
      └─ app/blog/[slug]/page.tsx

Result:
<RootLayout>
  <BlogLayout>
    <PostPage />
  </BlogLayout>
</RootLayout>

Layout Structure Example

See how layouts wrap pages at different levels

appImportant

Select a file or folder to see details

Creating Section-Specific Layouts

You can create layouts for specific sections of your app:

Example: Blog Layout

PLAINTEXT
app/
  layout.tsx              ← Root layout (header + footer)
  blog/
    layout.tsx            ← Blog layout (sidebar)
    page.tsx              → /blog
    [slug]/
      page.tsx            → /blog/my-post
app/blog/layout.tsx
import Link from 'next/link';

export default function BlogLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="container mx-auto px-4 py-8">
      <div className="grid grid-cols-1 lg:grid-cols-4 gap-8">
        {/* Sidebar - only shows on blog pages */}
        <aside className="lg:col-span-1">
          <div className="bg-white rounded-lg shadow p-6 sticky top-4">
            <h3 className="font-bold text-lg mb-4">Categories</h3>
            <nav className="space-y-2">
              <Link 
                href="/blog/category/tech"
                className="block text-blue-600 hover:underline"
              >
                Technology
              </Link>
              <Link 
                href="/blog/category/design"
                className="block text-blue-600 hover:underline"
              >
                Design
              </Link>
              <Link 
                href="/blog/category/business"
                className="block text-blue-600 hover:underline"
              >
                Business
              </Link>
            </nav>
            
            <h3 className="font-bold text-lg mt-6 mb-4">Recent Posts</h3>
            <div className="space-y-3 text-sm">
              <Link href="/blog/post-1" className="block hover:text-blue-600">
                Understanding Next.js Layouts
              </Link>
              <Link href="/blog/post-2" className="block hover:text-blue-600">
                Building with Server Components
              </Link>
            </div>
          </div>
        </aside>

        {/* Main content - blog pages render here */}
        <main className="lg:col-span-3">
          {children}
        </main>
      </div>
    </div>
  );
}

Now all blog pages have a sidebar, but other pages don't!

Example: Dashboard Layout

app/dashboard/layout.tsx
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="flex h-screen">
      {/* Sidebar navigation */}
      <aside className="w-64 bg-gray-900 text-white p-6">
        <h2 className="text-xl font-bold mb-6">Dashboard</h2>
        <nav className="space-y-2">
          <a href="/dashboard" className="block px-4 py-2 rounded hover:bg-gray-800">
            📊 Overview
          </a>
          <a href="/dashboard/analytics" className="block px-4 py-2 rounded hover:bg-gray-800">
            📈 Analytics
          </a>
          <a href="/dashboard/users" className="block px-4 py-2 rounded hover:bg-gray-800">
            👥 Users
          </a>
          <a href="/dashboard/settings" className="block px-4 py-2 rounded hover:bg-gray-800">
            ⚙️ Settings
          </a>
        </nav>
      </aside>

      {/* Main dashboard content */}
      <main className="flex-1 overflow-auto bg-gray-50 p-8">
        {children}
      </main>
    </div>
  );
}

Layout State Persists

One of the most powerful features of layouts is that their state persists across page navigations:

app/layout.tsx
'use client';

import { useState } from 'react';
import Link from 'next/link';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  // This state persists across page navigations!
  const [menuOpen, setMenuOpen] = useState(false);

  return (
    <html lang="en">
      <body>
        <header className="bg-blue-600 text-white p-4">
          <div className="flex items-center justify-between">
            <div className="text-xl font-bold">My App</div>
            
            {/* Mobile menu button */}
            <button
              onClick={() => setMenuOpen(!menuOpen)}
              className="lg:hidden"
            >
              {menuOpen ? '✕' : '☰'}
            </button>
            
            {/* Navigation */}
            <nav className={`${menuOpen ? 'block' : 'hidden'} lg:block`}>
              <Link href="/" className="mx-4">Home</Link>
              <Link href="/about" className="mx-4">About</Link>
              <Link href="/blog" className="mx-4">Blog</Link>
            </nav>
          </div>
        </header>

        <main>{children}</main>
      </body>
    </html>
  );
}

When you navigate between pages, the menuOpen state persists! If the menu is open and you navigate to another page, it stays open.

Why This Matters

Persistent state enables:

  • Better UX: UI state doesn't reset unexpectedly
  • Performance: Layout doesn't re-render on navigation
  • Smooth transitions: Sidebar, modals, etc. stay in place
  • Complex UI: Maintain application-level state

Client vs Server Components in Layouts

Server Component Layouts (Default)

By default, layouts are Server Components:

app/layout.tsx
// Server Component (default)
export default async function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  // Can fetch data
  const user = await fetch('https://api.example.com/user')
    .then(r => r.json());

  return (
    <html lang="en">
      <body>
        <header>
          <nav>
            {user ? `Welcome, ${user.name}` : 'Login'}
          </nav>
        </header>
        <main>{children}</main>
      </body>
    </html>
  );
}

Client Component Layouts (When Needed)

Add "use client" when you need interactivity:

app/layout.tsx
'use client';

import { useState } from 'react';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const [sidebarOpen, setSidebarOpen] = useState(true);

  return (
    <html lang="en">
      <body>
        <button onClick={() => setSidebarOpen(!sidebarOpen)}>
          Toggle Sidebar
        </button>
        
        <div className="flex">
          {sidebarOpen && <aside>Sidebar</aside>}
          <main>{children}</main>
        </div>
      </body>
    </html>
  );
}

Important: Choose Wisely

Making a layout a Client Component means all pages it wraps become Client Components too. Prefer:

  • Server Components for layouts when possible
  • Client Components only for interactive parts (move to separate components)

Best Practice: Separate Interactive Components

components/MobileMenu.tsx
'use client';

import { useState } from 'react';

export function MobileMenu() {
  const [open, setOpen] = useState(false);
  
  return (
    <>
      <button onClick={() => setOpen(!open)}>
        {open ? '✕' : '☰'}
      </button>
      {open && (
        <nav>
          {/* Menu items */}
        </nav>
      )}
    </>
  );
}
app/layout.tsx
// Server Component (better!)
import { MobileMenu } from '@/components/MobileMenu';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <header>
          <MobileMenu />  {/* Only this is a Client Component */}
        </header>
        <main>{children}</main>
      </body>
    </html>
  );
}

Common Layout Patterns

1. Marketing Site Layout

TYPESCRIPT
export default function MarketingLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <>
      <header className="sticky top-0 bg-white shadow">
        <nav>{/* Marketing navigation */}</nav>
      </header>
      
      <main>{children}</main>
      
      <footer className="bg-gray-900 text-white">
        {/* Footer with links, newsletter, etc. */}
      </footer>
    </>
  );
}

2. Application Layout (Sidebar)

TYPESCRIPT
export default function AppLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="flex h-screen">
      <aside className="w-64 bg-gray-900">
        {/* Sidebar navigation */}
      </aside>
      
      <div className="flex-1 flex flex-col">
        <header className="h-16 border-b">
          {/* Top bar */}
        </header>
        
        <main className="flex-1 overflow-auto p-8">
          {children}
        </main>
      </div>
    </div>
  );
}

3. Centered Content Layout

TYPESCRIPT
export default function CenteredLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="min-h-screen bg-gray-50 flex items-center justify-center p-4">
      <div className="w-full max-w-md">
        {children}
      </div>
    </div>
  );
}

4. Two-Column Layout

TYPESCRIPT
export default function TwoColumnLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="container mx-auto px-4 py-8">
      <div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
        <aside className="lg:col-span-1">
          {/* Sidebar content */}
        </aside>
        
        <main className="lg:col-span-2">
          {children}
        </main>
      </div>
    </div>
  );
}

Layout Best Practices

1. Keep Layouts Simple

Layouts should focus on structure and shared UI, not complex logic:

TYPESCRIPT
// ✅ Good: Simple, structural
export default function Layout({ children }) {
  return (
    <div>
      <Header />
      <main>{children}</main>
      <Footer />
    </div>
  );
}

Avoid putting too much logic in layouts:

TYPESCRIPT
// ❌ Avoid: Too much logic
export default function Layout({ children }) {
  // Don't put complex business logic here
  const complexCalculation = /* ... */;
  const processedData = /* ... */;
  
  return <div>{/* ... */}</div>;
}

2. Use Metadata for SEO

TYPESCRIPT
import { Metadata } from 'next';

export const metadata: Metadata = {
  title: {
    template: '%s | My App',  // Page titles will use this template
    default: 'My App',
  },
  description: 'Welcome to My App',
};

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

3. Compose Layouts, Don't Duplicate

Extract shared components instead of duplicating:

TYPESCRIPT
// components/AppHeader.tsx
export function AppHeader() {
  return <header>{/* Header UI */}</header>;
}

// Use in multiple layouts
import { AppHeader } from '@/components/AppHeader';

export default function Layout({ children }) {
  return (
    <div>
      <AppHeader />
      {children}
    </div>
  );
}

4. Consider Mobile Responsiveness

TYPESCRIPT
export default function Layout({ children }) {
  return (
    <div className="flex flex-col lg:flex-row">
      {/* Stack on mobile, side-by-side on desktop */}
      <aside className="w-full lg:w-64">
        Sidebar
      </aside>
      <main className="flex-1">
        {children}
      </main>
    </div>
  );
}

Practice: Build a Layout

Complete Layout Example

A full layout with header, footer, and responsive design

layout.tsx

Output Preview

Click "Run Code" to see the output

🎯 Challenge

Create these layouts in your project:

  1. Root layout with header and footer
  2. Blog layout with sidebar
  3. Dashboard layout with navigation
  4. Test that state persists when navigating

Key Takeaways

  • Layouts share UI across pages - no duplication needed
  • Use layout.tsx files - automatically wrap pages
  • Receive children prop - page content renders there
  • State persists across navigation - layouts don't re-render
  • Can nest layouts - root layout + section layouts
  • Server Components by default - use "use client" when needed
  • Extract interactive components - keep layouts as Server Components
  • Keep layouts simple - focus on structure, not logic

What's Next?

You've learned the fundamentals of layouts! But there's a special layout that's required in every Next.js app—the root layout. In the next lesson, we'll dive deep into the root layout and learn how to configure global settings, manage the HTML and body tags, and set up app-wide configurations.

Understanding the root layout is crucial because it's the foundation of your entire application. Let's master it!

🎓 Practice Makes Perfect

Layouts are fundamental to Next.js. Take time to experiment with different layout patterns in your project. Try creating layouts for different sections and see how they compose together!

Test Your Understanding

Question 1 of 4

What is the primary purpose of layout.tsx files in Next.js?

Master Next.js layouts! Learn how to create shared UI that persists across pages.

Previous
Intercepting Routes
Next
Root Layout and Global Configuration

Master Next.js Layouts

Join 2,000+ developers building with Next.js. Get the next lesson on root layouts delivered to your inbox - absolutely FREE.

You might also like

UI Components

Ready-made components for your projects

Developer Tools

Boost productivity with handy generators

HTML Game

Learn HTML concepts through interactive gameplay

Join Our Web Development Training Program

Master frontend & backend development with hands-on projects.

NextJS Tutorials

0 of 70 completed

Your Progress0%

Topics

Getting Started

  • What is Next.js?
  • Next.js vs React - Key Differences
  • Creating Your First Next.js 15 Project
  • Next.js Project Structure Explained
  • App Router vs Pages Router

Routing Fundamentals

  • File-Based Routing Basics
  • Creating Pages with page.tsx
  • Dynamic Routes and Route Parameters
  • Catch-All and Optional Catch-All Routes
  • Route Groups for Organization
  • Parallel Routes
  • Intercepting Routes

Layouts and Pages

  • Understanding Layouts
  • Root Layout and Global Configuration
  • Nested Layouts
  • Templates vs Layouts
  • Loading States with loading.tsx
  • Error Handling with error.tsx

Server and Client Components

  • Understanding Server Components
  • Client Components with 'use client'
  • When to Use Server vs Client Components
  • Component Composition Patterns
  • Passing Props Between Server and Client
  • Server Component Patterns and Best Practices

Data Fetching

  • Fetching Data in Server Components
  • Parallel and Sequential Data Fetching
  • Data Fetching Patterns and Strategies
  • Caching and Revalidation
  • Revalidate and Cache Tags
  • Handling Loading and Error States in Data Fetching

Navigation and Links

  • Link Component Basics
  • useRouter Hook for Programmatic Navigation
  • usePathname and useSearchParams Hooks
  • Active Links and Navigation States
  • Redirects and Navigation Guards

Styling in Next.js

  • CSS Modules in Next.js
  • Tailwind CSS Setup and Configuration
  • Global Styles and CSS Variables
  • Next.js Font Optimization

Images and Media

  • Next.js Image Component Basics
  • Image Optimization and Best Practices
  • Working with Static Assets

Forms and Data Mutations

  • Understanding Server Actions
  • Form Handling with Server Actions
  • Form Validation and Error Handling
  • useFormStatus and useFormState Hooks
  • Revalidating Data After Mutations
  • Optimistic Updates

Metadata and SEO

  • Static Metadata Configuration
  • Dynamic Metadata Generation
  • Open Graph and Social Media Cards
  • Sitemap and Robots.txt

API Routes and Route Handlers

  • Route Handlers Introduction
  • GET and POST Request Handlers
  • Dynamic API Routes
  • Request and Response Objects
  • API Error Handling and Status Codes

Middleware and Advanced Features

  • Introduction to Middleware
  • Authentication with Middleware
  • Environment Variables and Configuration
  • Streaming and Suspense
  • Not Found and Global Error Pages

Deployment and Optimization

  • Understanding Static and Dynamic Rendering
  • generateStaticParams for Static Generation
  • Build and Production Optimization
  • Deploying to Vercel
  • Alternative Deployment Options
  • Performance Monitoring and Analytics

Real-World Projects

  • Project 1: E-commerce Product Catalog
  • Project 2: Dashboard with Authentication
Falytom logoFALYTOM

Learn technologies like HTML, CSS, JavaScript, React, NodeJS and more through interactive games, tutorials, components and free tools. Transform your businesses with AI chatbots, SEO-optimized websites, and professional development services.

© 2025 Tomilola Group
  • Facebook logo
  • Twitter logo
  • Instagram logo
  • LinkedIn logo
  • GitHub logo
  • YouTube logo