Creating New Pages

Learn how to add entirely new pages to the K12worX website, from simple static pages to dynamic routes.

What You'll Learn

  • Next.js 15 App Router file structure
  • Creating static pages
  • Adding pages to navigation
  • Dynamic routes with parameters
  • Layout and metadata

NextJS Page Basics

How Pages Work

In Next.js 15, pages are created by:

  1. Creating a folder in app/
  2. Adding a page.tsx file
  3. Exporting a default component

The folder name becomes the URL!

File Structure

app/
├── page.tsx           → /
├── about/
│   └── page.tsx       → /about
├── contact/
│   └── page.tsx       → /contact
└── blog/
    ├── page.tsx       → /blog
    └── [slug]/
        └── page.tsx   → /blog/post-title

Exercise 1: Create a Simple Page

Step 1: Create Folder

# In your project root
mkdir -p app/team

Step 2: Create page.tsx

Create app/team/page.tsx:

export default function TeamPage() {
  return (
    <div className="min-h-screen bg-white">
      <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
        <h1 className="text-4xl font-bold text-gray-900 mb-6">
          Our Team
        </h1>
        <p className="text-lg text-gray-600">
          Meet the K12worX team members working to make education accessible.
        </p>
      </div>
    </div>
  );
}

Step 3: View Your Page

Navigate to: http://localhost:3000/team

It works! That's a new page.

Step 4: Add to Navigation

Edit components/layout/Navigation.tsx:

const navItems = [
  // ... existing items ...
  { name: "Team", href: "/team" },
];

Adding Metadata

Page Title and Description

Add metadata to your page:

import { Metadata } from 'next';

export const metadata: Metadata = {
  title: 'Our Team | K12worX',
  description: 'Meet the K12worX team dedicated to educational equity',
};

export default function TeamPage() {
  return (
    // ... page content ...
  );
}

Now:

  • Browser tab shows "Our Team | K12worX"
  • Meta description for SEO

Using Layouts

Option 1: Use Default Layout

Most pages should use existing layouts:

import DefaultLayout from '@/components/layout/DefaultLayout';

export default function TeamPage() {
  return (
    <DefaultLayout>
      <h1>Our Team</h1>
      <p>Content here</p>
    </DefaultLayout>
  );
}

Option 2: Create Custom Layout

For special pages, create app/team/layout.tsx:

export default function TeamLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="bg-gradient-to-b from-blue-50 to-white min-h-screen">
      <div className="max-w-7xl mx-auto px-4 py-12">
        {children}
      </div>
    </div>
  );
}

Exercise 2: Page with Components

Create a More Complex Page

import { Metadata } from 'next';
import Link from 'next/link';

export const metadata: Metadata = {
  title: 'Volunteer | K12worX',
  description: 'Join our volunteer tutoring program',
};

export default function VolunteerPage() {
  return (
    <div className="min-h-screen bg-white">
      {/* Hero Section */}
      <section className="bg-blue-600 text-white py-20">
        <div className="max-w-7xl mx-auto px-4 text-center">
          <h1 className="text-5xl font-bold mb-6">
            Become a Tutor
          </h1>
          <p className="text-xl mb-8">
            Help K-8 students achieve their potential
          </p>
          <Link
            href="/get-involved"
            className="inline-block px-8 py-3 bg-white text-blue-600 font-semibold rounded-lg hover:bg-gray-100 transition"
          >
            Get Started
          </Link>
        </div>
      </section>

      {/* Benefits Section */}
      <section className="py-16">
        <div className="max-w-7xl mx-auto px-4">
          <h2 className="text-3xl font-bold text-center mb-12">
            Why Volunteer?
          </h2>

          <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
            <div className="text-center p-6">
              <div className="text-4xl mb-4">🎓</div>
              <h3 className="text-xl font-semibold mb-2">
                Make an Impact
              </h3>
              <p className="text-gray-600">
                Help students overcome educational barriers
              </p>
            </div>

            <div className="text-center p-6">
              <div className="text-4xl mb-4">💡</div>
              <h3 className="text-xl font-semibold mb-2">
                Develop Skills
              </h3>
              <p className="text-gray-600">
                Build leadership and teaching abilities
              </p>
            </div>

            <div className="text-center p-6">
              <div className="text-4xl mb-4">🤝</div>
              <h3 className="text-xl font-semibold mb-2">
                Join Community
              </h3>
              <p className="text-gray-600">
                Connect with like-minded students
              </p>
            </div>
          </div>
        </div>
      </section>
    </div>
  );
}

Dynamic Routes

Creating Dynamic Pages

For pages with variable URLs (like blog posts):

Structure:

app/blog/[slug]/page.tsx  → /blog/any-post-name

Example - app/blog/[slug]/page.tsx:

interface PageProps {
  params: Promise<{
    slug: string;
  }>;
}

export default async function BlogPostPage({ params }: PageProps) {
  const { slug } = await params;

  return (
    <div className="max-w-4xl mx-auto px-4 py-12">
      <h1 className="text-4xl font-bold mb-6">
        Blog Post: {slug}
      </h1>
      <p>URL slug: {slug}</p>
    </div>
  );
}

Now:

  • /blog/my-first-post → shows "my-first-post"
  • /blog/hello-world → shows "hello-world"

Generate Static Pages

For pre-rendering specific slugs:

export async function generateStaticParams() {
  return [
    { slug: 'introduction' },
    { slug: 'getting-started' },
    { slug: 'first-tutorial' },
  ];
}

NextJS will pre-render these three pages at build time.

Nested Routes

Multi-Level Pages

app/
└── resources/
    ├── page.tsx              → /resources
    └── guides/
        ├── page.tsx          → /resources/guides
        └── [category]/
            └── page.tsx      → /resources/guides/math

Each level can have its own page and layout.

Page Templates

Template 1: Simple Content Page

import { Metadata } from 'next';

export const metadata: Metadata = {
  title: 'FAQ | K12worX',
};

export default function FAQPage() {
  return (
    <div className="max-w-4xl mx-auto px-4 py-12">
      <h1 className="text-4xl font-bold mb-8">
        Frequently Asked Questions
      </h1>

      <div className="space-y-6">
        <div>
          <h2 className="text-2xl font-semibold mb-2">
            What is K12worX?
          </h2>
          <p className="text-gray-600">
            K12worX is a student-powered tutoring network...
          </p>
        </div>

        {/* More Q&A items */}
      </div>
    </div>
  );
}

Template 2: Grid Layout Page

export default function ResourcesPage() {
  const resources = [
    { title: 'Study Guide', icon: '📚', link: '/resources/study-guide' },
    { title: 'Videos', icon: '🎥', link: '/resources/videos' },
    { title: 'Practice', icon: '✏️', link: '/resources/practice' },
  ];

  return (
    <div className="max-w-7xl mx-auto px-4 py-12">
      <h1 className="text-4xl font-bold mb-12">Resources</h1>

      <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
        {resources.map((resource) => (
          <Link
            key={resource.title}
            href={resource.link}
            className="p-6 bg-white border rounded-lg hover:shadow-lg transition"
          >
            <div className="text-4xl mb-4">{resource.icon}</div>
            <h2 className="text-xl font-semibold">{resource.title}</h2>
          </Link>
        ))}
      </div>
    </div>
  );
}

Best Practices

1. Consistent Structure

Use the same container pattern:

<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
  {/* Content */}
</div>

2. Add Metadata

Every page should have:

  • title
  • description

3. Use Semantic HTML

// ✅ Good
<main>
  <section>
    <h1>Title</h1>
  </section>
</main>

// ❌ Bad
<div>
  <div>
    <div>Title</div>
  </div>
</div>

4. Mobile-First Styling

// ✅ Good: Mobile first, then larger
<div className="text-2xl md:text-4xl">

// ❌ Desktop first
<div className="text-4xl md:text-2xl">

Quick Reference

Create page:

app/pagename/page.tsx

Add metadata:

export const metadata: Metadata = {
  title: 'Page Title',
  description: 'Description',
};

Dynamic route:

app/blog/[slug]/page.tsx

Access params:

const { slug } = await params;

Generate static pages:

export async function generateStaticParams() {
  return [{ slug: 'post-1' }];
}

What's Next

Now that you can create pages, let's learn to build reusable components:

Building Components →