WDD 430: Web Full-Stack Development

Creating Layouts and Pages

Overview

In the Next.js App Router, folders define routes and layout.tsx files define a shared UI. In this activity, you will learn how nested routes work, how nested layouts compose, and why layout persistence improves the navigation experience. The goal is to create a well-structured, maintainable layout system for a Next.js application.

Prepare

For this activity, use the portfolio app you created in Week 01.
The following diagram shows the existing app/ layout.

app/
  ├── about/ 
  │   └── page.tsx     
  ├── api/
  │   └── hello/
  │       └── route.ts
  ├── favicon.ico
  ├── globals.css
  ├── layout.tsx
  └── page.tsx                         
                   
              

In this activity, you will extend that existing structure by adding a new projects section to demonstrate nested routes and nested layouts.

app/
  ├── about/
  │   └── page.tsx
  ├── api/
  │   └── hello/
  │     └── route.ts
  ├── projects/
  │   ├── layout.tsx        ⬅️ new section layout
  │   ├── page.tsx          ⬅️ overview page
  │   └── opensource/       ⬅️ open source projects
  │   │   └── page.tsx
  │   └── school/           ⬅️ school projects
  │       └── page.tsx
  ├── favicon.ico
  ├── globals.css
  ├── layout.tsx
  └── page.tsx

Layout Composition (Root + Nested)

Your portfolio app already uses a root layout in app/layout.tsx. A nested layout (such as app/projects/layout.tsx) only applies to the nested route within it. This keeps shared UI in one place and reduces duplicate code.

Root Layout (app/layout.tsx)
└── Projects Layout (app/projects/layout.tsx)
    ├── Projects Overview Page  (app/projects/page.tsx)
    ├── Open Source Projects Page (app/projects/opensource/page.tsx)
    └── School Projects Page (app/projects/school/page.tsx)

In your portfolio app, this pattern lets the root layout keep global UI sections like the header and footer, while the projects layout adds section-specific navigation.

// app/layout.tsx
import "./globals.css";
import Header from "@/components/Header";
import Footer from "@/components/Footer";


export default function RootLayout({ children }: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className="bg-gray-50 dark:bg-gray-900">
        <Header />  {/* Global header component */}
        {children}
        <Footer />  {/* Global footer component */}
      </body>
    </html>
  );
}
// app/projects/layout.tsx

import Link from 'next/link';

export default function ProjectsLayout({ children }: { children: React.ReactNode }) {
  return (
    <section>
      <nav>
        <Link href="/projects">Overview</Link> | {' '}
        <Link href="/projects/opensource">Open Source</Link> | {' '}
        <Link href="/projects/school">School</Link>
      </nav>
      {children}
    </section>
  );
}

Route Groups and Partial Rendering

Route groups are folders wrapped in parentheses, such as (public) or (portfolio). They organize routes without changing the URL path, and they are often used to group routes by purpose or by layout strategy.

app/
  ├── (public)/
  │   ├── page.tsx                → /
  │   └── about/
  │       └── page.tsx            → /about
  ├── (portfolio)/
  │   └── projects/
  │       ├── layout.tsx          → shared only for /projects/*
  │       ├── page.tsx            → /projects
  │       ├── opensource/
  │       │   └── page.tsx        → /projects/opensource
  │       └── school/
  │           └── page.tsx        → /projects/school
  └── api/
    └── hello/
      └── route.ts            → /api/hello

Partial rendering means Next.js updates only the route segment that changes during client-side navigation. For example, when moving between /projects, /projects/opensource, and /projects/school, the root layout and app/projects/layout.tsx stay mounted while only the page segment is replaced. If you navigate from /projects to /about, the projects layout no longer applies, so that nested layout is removed and the route renders with only the layouts shared by both paths.

Activity Instructions

  1. Open your wdd430-portfolio project folder and run npm run dev
  2. Confirm your existing routes and files are working before you add anything new:
    • / from app/page.tsx
    • /about from app/about/page.tsx
    • /api/hello from app/api/hello/route.ts
    • Global layout from app/layout.tsx
  3. Create a new folder: app/projects/. Add app/projects/page.tsx with a heading such as "Projects Overview."
  4. Create app/projects/layout.tsx. Add section-specific UI, including links to /projects and /projects/settings, and render {children}.
  5. Create app/projects/opensource/page.tsx with a different heading such as "Open Source Projects."
  6. Create app/projects/school/page.tsx with a different heading such as "School Projects."
  7. Update your global navigation (in your existing header component or directly in app/layout.tsx) to include a link to /projects.
  8. Test this navigation sequence and observe what persists:
    • /projects
    • /projects/opensource
    • /projects/school
    Verify that root layout UI remains across all routes, while projects layout UI appears only inside /projects/* routes.
  9. Consider what belongs in app/layout.tsx versus app/projects/layout.tsx, and why?
Check Your Understanding

Example portfolio app