Falytom logoFALYTOM
Games
ToolsUI ComponentsServicesProductsAbout
menu
  1. Home
  2. /Web Development
  3. /Nextjs
  4. /Active Links
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

Active Links and Navigation States

Highlighting active links and managing navigation states

Professional navigation requires visual feedback. Users need to know where they are in your application and when navigation is happening. Active link highlighting shows the current page, loading indicators show navigation progress, and hover states provide interactive feedback. Let's build navigation components that feel polished and professional with proper active states, loading indicators, and smooth transitions!

Basic Active Link Pattern

Simple Active Link Component

components/NavLink.tsx
'use client';

import Link from 'next/link';
import { usePathname } from 'next/navigation';

interface NavLinkProps {
  href: string;
  children: React.ReactNode;
}

export function NavLink({ href, children }: NavLinkProps) {
  const pathname = usePathname();
  const isActive = pathname === href;

  return (
    <Link
      href={href}
      className={
        isActive
          ? 'text-blue-600 font-semibold border-b-2 border-blue-600'
          : 'text-gray-700 hover:text-blue-600 transition'
      }
    >
      {children}
    </Link>
  );
}

// Usage:
// <NavLink href="/about">About</NavLink>
// <NavLink href="/blog">Blog</NavLink>

// ✅ Compares current pathname with href
// ✅ Different styles for active vs inactive
// ✅ Hover effect on inactive links

Active Link with Exact vs Partial Match

components/NavLink.tsx
'use client';

import Link from 'next/link';
import { usePathname } from 'next/navigation';

interface NavLinkProps {
  href: string;
  children: React.ReactNode;
  exact?: boolean; // Default false
}

export function NavLink({ href, children, exact = false }: NavLinkProps) {
  const pathname = usePathname();
  
  // Exact match: pathname must equal href exactly
  // Partial match: pathname starts with href (for nested routes)
  const isActive = exact 
    ? pathname === href
    : pathname === href || pathname.startsWith(href + '/');

  return (
    <Link
      href={href}
      className={`px-4 py-2 rounded-lg transition ${
        isActive
          ? 'bg-blue-600 text-white font-semibold'
          : 'text-gray-700 hover:bg-gray-100'
      }`}
    >
      {children}
    </Link>
  );
}

// Usage:
// <NavLink href="/" exact>Home</NavLink>           // Only active on "/"
// <NavLink href="/blog">Blog</NavLink>             // Active on "/blog/*"
// <NavLink href="/about" exact>About</NavLink>     // Only active on "/about"

// Examples:
// URL: / → Home is active
// URL: /blog → Blog is active
// URL: /blog/post-1 → Blog is STILL active (partial match)
// URL: /about → About is active

// ✅ Exact match for home and specific pages
// ✅ Partial match for sections with nested routes
// ✅ Flexible active state logic

Advanced Active Link Styling

Multiple Style Variants

components/NavLink.tsx
'use client';

import Link from 'next/link';
import { usePathname } from 'next/navigation';

type Variant = 'default' | 'pill' | 'underline' | 'sidebar';

interface NavLinkProps {
  href: string;
  children: React.ReactNode;
  variant?: Variant;
  exact?: boolean;
}

export function NavLink({ 
  href, 
  children, 
  variant = 'default',
  exact = false 
}: NavLinkProps) {
  const pathname = usePathname();
  const isActive = exact 
    ? pathname === href
    : pathname === href || pathname.startsWith(href + '/');

  const styles = {
    default: isActive
      ? 'text-blue-600 font-semibold'
      : 'text-gray-700 hover:text-blue-600',
    
    pill: isActive
      ? 'bg-blue-600 text-white px-4 py-2 rounded-full font-semibold'
      : 'text-gray-700 hover:bg-gray-100 px-4 py-2 rounded-full',
    
    underline: isActive
      ? 'text-blue-600 font-semibold border-b-2 border-blue-600 pb-1'
      : 'text-gray-700 hover:text-blue-600 hover:border-b-2 hover:border-gray-300 pb-1',
    
    sidebar: isActive
      ? 'bg-blue-50 text-blue-600 font-semibold border-l-4 border-blue-600 px-4 py-2'
      : 'text-gray-700 hover:bg-gray-50 hover:border-l-4 hover:border-gray-300 px-4 py-2',
  };

  return (
    <Link href={href} className={`${styles[variant]} transition`}>
      {children}
    </Link>
  );
}

// Usage:
// <NavLink href="/blog" variant="pill">Blog</NavLink>
// <NavLink href="/about" variant="underline">About</NavLink>
// <NavLink href="/docs" variant="sidebar">Docs</NavLink>

// ✅ Multiple design patterns
// ✅ Consistent active states
// ✅ Smooth transitions
// ✅ Reusable component

Active Link with Icon

components/NavLink.tsx
'use client';

import Link from 'next/link';
import { usePathname } from 'next/navigation';

interface NavLinkProps {
  href: string;
  icon: React.ReactNode;
  children: React.ReactNode;
  exact?: boolean;
}

export function NavLinkWithIcon({ 
  href, 
  icon, 
  children, 
  exact = false 
}: NavLinkProps) {
  const pathname = usePathname();
  const isActive = exact 
    ? pathname === href
    : pathname === href || pathname.startsWith(href + '/');

  return (
    <Link
      href={href}
      className={`flex items-center gap-3 px-4 py-3 rounded-lg transition ${
        isActive
          ? 'bg-blue-600 text-white font-semibold'
          : 'text-gray-700 hover:bg-gray-100'
      }`}
    >
      <span className={`text-xl ${isActive ? 'opacity-100' : 'opacity-60'}`}>
        {icon}
      </span>
      <span>{children}</span>
      {isActive && (
        <span className="ml-auto">✓</span>
      )}
    </Link>
  );
}

// Usage:
// <NavLinkWithIcon href="/dashboard" icon={<DashboardIcon />}>
//   Dashboard
// </NavLinkWithIcon>
// <NavLinkWithIcon href="/settings" icon={<SettingsIcon />}>
//   Settings
// </NavLinkWithIcon>

// ✅ Icon included in component
// ✅ Icon opacity changes with active state
// ✅ Checkmark indicator when active
// ✅ Professional sidebar navigation

Nested Navigation with Active States

Sidebar with Nested Links

components/Sidebar.tsx
'use client';

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

interface NavItem {
  href: string;
  label: string;
  children?: NavItem[];
}

const navigation: NavItem[] = [
  { href: '/dashboard', label: 'Dashboard' },
  { 
    href: '/products', 
    label: 'Products',
    children: [
      { href: '/products/list', label: 'All Products' },
      { href: '/products/new', label: 'Add Product' },
      { href: '/products/categories', label: 'Categories' },
    ],
  },
  { 
    href: '/orders', 
    label: 'Orders',
    children: [
      { href: '/orders/pending', label: 'Pending' },
      { href: '/orders/completed', label: 'Completed' },
    ],
  },
  { href: '/settings', label: 'Settings' },
];

function NavItem({ item }: { item: NavItem }) {
  const pathname = usePathname();
  const [isOpen, setIsOpen] = useState(
    pathname.startsWith(item.href)
  );

  const isActive = pathname === item.href || pathname.startsWith(item.href + '/');
  const isExactMatch = pathname === item.href;

  return (
    <div>
      {/* Parent Link */}
      <div className="flex items-center">
        <Link
          href={item.href}
          className={`flex-1 flex items-center gap-3 px-4 py-3 rounded-lg transition ${
            isExactMatch
              ? 'bg-blue-600 text-white font-semibold'
              : isActive
              ? 'bg-blue-50 text-blue-600 font-semibold'
              : 'text-gray-700 hover:bg-gray-100'
          }`}
        >
          {item.label}
        </Link>

        {/* Expand/Collapse Button */}
        {item.children && (
          <button
            onClick={() => setIsOpen(!isOpen)}
            className="p-2 hover:bg-gray-100 rounded"
          >
            <span className={`transition-transform ${isOpen ? 'rotate-180' : ''}`}>
              ▼
            </span>
          </button>
        )}
      </div>

      {/* Nested Links */}
      {item.children && isOpen && (
        <div className="ml-6 mt-1 space-y-1">
          {item.children.map(child => {
            const isChildActive = pathname === child.href;

            return (
              <Link
                key={child.href}
                href={child.href}
                className={`block px-4 py-2 rounded-lg transition ${
                  isChildActive
                    ? 'bg-blue-600 text-white font-semibold'
                    : 'text-gray-600 hover:bg-gray-100'
                }`}
              >
                {child.label}
              </Link>
            );
          })}
        </div>
      )}
    </div>
  );
}

export function Sidebar() {
  return (
    <aside className="w-64 h-screen bg-white border-r p-4">
      <div className="space-y-2">
        {navigation.map(item => (
          <NavItem key={item.href} item={item} />
        ))}
      </div>
    </aside>
  );
}

// ✅ Nested navigation with expand/collapse
// ✅ Parent link highlighted when on child route
// ✅ Auto-expands when on nested route
// ✅ Smooth transitions
// ✅ Professional sidebar navigation

Loading States During Navigation

Navigation Loading Indicator with useTransition

components/NavLinkWithLoading.tsx
'use client';

import Link from 'next/link';
import { usePathname, useRouter } from 'next/navigation';
import { useTransition } from 'react';

interface NavLinkProps {
  href: string;
  children: React.ReactNode;
}

export function NavLinkWithLoading({ href, children }: NavLinkProps) {
  const pathname = usePathname();
  const router = useRouter();
  const [isPending, startTransition] = useTransition();

  const isActive = pathname === href;

  const handleClick = (e: React.MouseEvent) => {
    e.preventDefault();
    startTransition(() => {
      router.push(href);
    });
  };

  return (
    <Link
      href={href}
      onClick={handleClick}
      className={`relative px-4 py-2 rounded-lg transition ${
        isActive
          ? 'bg-blue-600 text-white font-semibold'
          : 'text-gray-700 hover:bg-gray-100'
      } ${isPending ? 'opacity-50 cursor-wait' : ''}`}
    >
      {children}
      {isPending && (
        <span className="absolute right-2 top-1/2 -translate-y-1/2">
          <span className="inline-block w-4 h-4 border-2 border-current border-t-transparent rounded-full animate-spin" />
        </span>
      )}
    </Link>
  );
}

// ✅ Shows spinner during navigation
// ✅ Dims link while loading
// ✅ Cursor changes to wait
// ✅ Better user feedback

Global Navigation Loading Bar

components/LoadingBar.tsx
'use client';

import { useEffect, useState } from 'react';
import { usePathname } from 'next/navigation';

export function LoadingBar() {
  const pathname = usePathname();
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    // Show loading bar
    setLoading(true);

    // Hide after short delay (simulates loading)
    const timer = setTimeout(() => {
      setLoading(false);
    }, 300);

    return () => clearTimeout(timer);
  }, [pathname]);

  if (!loading) return null;

  return (
    <div className="fixed top-0 left-0 right-0 h-1 bg-blue-600 z-50 animate-pulse">
      <div className="h-full bg-blue-400 animate-[loading_1s_ease-in-out_infinite]" />
    </div>
  );
}

// Add to layout.tsx:
// export default function RootLayout({ children }) {
//   return (
//     <html>
//       <body>
//         <LoadingBar />
//         {children}
//       </body>
//     </html>
//   );
// }

// ✅ Shows at top of page during navigation
// ✅ Automatic - no configuration needed
// ✅ Smooth animation
// ✅ Non-intrusive visual feedback

Loading State with Progress

components/ProgressBar.tsx
'use client';

import { useEffect, useState } from 'react';
import { usePathname } from 'next/navigation';

export function ProgressBar() {
  const pathname = usePathname();
  const [progress, setProgress] = useState(0);
  const [visible, setVisible] = useState(false);

  useEffect(() => {
    // Reset and show
    setProgress(0);
    setVisible(true);

    // Animate progress
    const interval = setInterval(() => {
      setProgress(prev => {
        if (prev >= 90) {
          clearInterval(interval);
          return prev;
        }
        return prev + 10;
      });
    }, 100);

    // Complete after route change
    const timer = setTimeout(() => {
      setProgress(100);
      setTimeout(() => setVisible(false), 200);
    }, 500);

    return () => {
      clearInterval(interval);
      clearTimeout(timer);
    };
  }, [pathname]);

  if (!visible) return null;

  return (
    <div className="fixed top-0 left-0 right-0 h-1 bg-gray-200 z-50">
      <div
        className="h-full bg-blue-600 transition-all duration-200"
        style={{ width: `${progress}%` }}
      />
    </div>
  );
}

// ✅ Realistic progress animation
// ✅ Completes when navigation finishes
// ✅ Smooth transitions
// ✅ Professional loading feedback

Complete Navigation Examples

Example 1: Complete Navbar with Active Links

components/Navbar.tsx
'use client';

import Link from 'next/link';
import { usePathname } from 'next/navigation';

const links = [
  { href: '/', label: 'Home', exact: true },
  { href: '/about', label: 'About', exact: true },
  { href: '/blog', label: 'Blog', exact: false },
  { href: '/products', label: 'Products', exact: false },
  { href: '/contact', label: 'Contact', exact: true },
];

export function Navbar() {
  const pathname = usePathname();

  return (
    <nav className="bg-white shadow-md">
      <div className="container mx-auto px-4">
        <div className="flex items-center justify-between h-16">
          {/* Logo */}
          <Link href="/" className="text-2xl font-bold text-blue-600">
            MyApp
          </Link>

          {/* Navigation Links */}
          <ul className="flex gap-1">
            {links.map(link => {
              const isActive = link.exact
                ? pathname === link.href
                : pathname === link.href || pathname.startsWith(link.href + '/');

              return (
                <li key={link.href}>
                  <Link
                    href={link.href}
                    className={`px-4 py-2 rounded-lg transition font-medium ${
                      isActive
                        ? 'bg-blue-600 text-white'
                        : 'text-gray-700 hover:bg-gray-100'
                    }`}
                  >
                    {link.label}
                  </Link>
                </li>
              );
            })}
          </ul>

          {/* CTA Button */}
          <Link
            href="/signup"
            className="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition font-semibold"
          >
            Sign Up
          </Link>
        </div>
      </div>
    </nav>
  );
}

// ✅ Clean, professional navbar
// ✅ Active link highlighting
// ✅ Exact match for specific pages
// ✅ Partial match for sections
// ✅ Hover effects
// ✅ Responsive design ready

Example 2: Tabs with Active State

components/Tabs.tsx
'use client';

import Link from 'next/link';
import { usePathname } from 'next/navigation';

interface Tab {
  href: string;
  label: string;
  count?: number;
}

interface TabsProps {
  tabs: Tab[];
  basePath: string;
}

export function Tabs({ tabs, basePath }: TabsProps) {
  const pathname = usePathname();

  return (
    <div className="border-b border-gray-200">
      <nav className="flex gap-8">
        {tabs.map(tab => {
          const isActive = pathname === tab.href;

          return (
            <Link
              key={tab.href}
              href={tab.href}
              className={`pb-4 px-1 border-b-2 transition ${
                isActive
                  ? 'border-blue-600 text-blue-600 font-semibold'
                  : 'border-transparent text-gray-600 hover:text-gray-900 hover:border-gray-300'
              }`}
            >
              <span>{tab.label}</span>
              {tab.count !== undefined && (
                <span
                  className={`ml-2 px-2 py-1 text-xs rounded-full ${
                    isActive
                      ? 'bg-blue-100 text-blue-600'
                      : 'bg-gray-100 text-gray-600'
                  }`}
                >
                  {tab.count}
                </span>
              )}
            </Link>
          );
        })}
      </nav>
    </div>
  );
}

// Usage:
// <Tabs
//   basePath="/dashboard"
//   tabs={[
//     { href: '/dashboard/overview', label: 'Overview' },
//     { href: '/dashboard/analytics', label: 'Analytics', count: 12 },
//     { href: '/dashboard/reports', label: 'Reports', count: 3 },
//   ]}
// />

// ✅ Tab-style navigation
// ✅ Active border indicator
// ✅ Optional count badges
// ✅ Hover effects
// ✅ Clean, modern design

Example 3: Mobile Menu with Active States

components/MobileMenu.tsx
'use client';

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

const links = [
  { href: '/', label: 'Home' },
  { href: '/about', label: 'About' },
  { href: '/blog', label: 'Blog' },
  { href: '/products', label: 'Products' },
  { href: '/contact', label: 'Contact' },
];

export function MobileMenu() {
  const pathname = usePathname();
  const [isOpen, setIsOpen] = useState(false);

  return (
    <div className="lg:hidden">
      {/* Hamburger Button */}
      <button
        onClick={() => setIsOpen(!isOpen)}
        className="p-2 hover:bg-gray-100 rounded-lg"
        aria-label="Toggle menu"
      >
        <svg
          className="w-6 h-6"
          fill="none"
          stroke="currentColor"
          viewBox="0 0 24 24"
        >
          {isOpen ? (
            <path
              strokeLinecap="round"
              strokeLinejoin="round"
              strokeWidth={2}
              d="M6 18L18 6M6 6l12 12"
            />
          ) : (
            <path
              strokeLinecap="round"
              strokeLinejoin="round"
              strokeWidth={2}
              d="M4 6h16M4 12h16M4 18h16"
            />
          )}
        </svg>
      </button>

      {/* Mobile Menu Overlay */}
      {isOpen && (
        <>
          {/* Backdrop */}
          <div
            className="fixed inset-0 bg-black/50 z-40"
            onClick={() => setIsOpen(false)}
          />

          {/* Menu */}
          <div className="fixed top-0 right-0 bottom-0 w-64 bg-white shadow-xl z-50 p-6">
            <button
              onClick={() => setIsOpen(false)}
              className="absolute top-4 right-4 p-2 hover:bg-gray-100 rounded-lg"
            >
              ✕
            </button>

            <nav className="mt-12 space-y-2">
              {links.map(link => {
                const isActive =
                  pathname === link.href ||
                  (link.href !== '/' && pathname.startsWith(link.href));

                return (
                  <Link
                    key={link.href}
                    href={link.href}
                    onClick={() => setIsOpen(false)}
                    className={`block px-4 py-3 rounded-lg transition ${
                      isActive
                        ? 'bg-blue-600 text-white font-semibold'
                        : 'text-gray-700 hover:bg-gray-100'
                    }`}
                  >
                    {link.label}
                  </Link>
                );
              })}
            </nav>
          </div>
        </>
      )}
    </div>
  );
}

// ✅ Mobile-friendly navigation
// ✅ Slide-in menu
// ✅ Active link highlighting
// ✅ Backdrop overlay
// ✅ Close on link click
// ✅ Accessible (aria-label)

Active Links Project Structure

Organized navigation components with active states

componentsImportant

Select a file or folder to see details

Best Practices

1. Use Exact Match Wisely

TYPESCRIPT
// ✅ GOOD: Exact match for home
<NavLink href="/" exact>Home</NavLink>

// ✅ GOOD: Partial match for sections
<NavLink href="/blog">Blog</NavLink>
// Active on /blog, /blog/post-1, /blog/tech, etc.

// ❌ BAD: Partial match for home
<NavLink href="/">Home</NavLink>
// Would be active on EVERY page!

2. Provide Visual Feedback

TYPESCRIPT
// ✅ GOOD: Multiple visual cues
const activeStyles = 'bg-blue-600 text-white font-semibold border-l-4 border-blue-800';
const inactiveStyles = 'text-gray-700 hover:bg-gray-100';

// Color + font weight + border = clear active state

// ❌ BAD: Subtle difference only
const activeStyles = 'text-blue-600';
const inactiveStyles = 'text-gray-600';
// Too subtle - hard to see which is active

3. Show Loading States

TYPESCRIPT
// ✅ GOOD: Loading indicator during navigation
{isPending && <Spinner />}

// ✅ GOOD: Global loading bar
<LoadingBar />

// Provides feedback that navigation is happening

4. Make Touch Targets Large Enough

TYPESCRIPT
// ✅ GOOD: Large enough for mobile
<Link className="px-4 py-3"> {/* 44px+ height */}
  Link Text
</Link>

// ❌ BAD: Too small
<Link className="px-2 py-1"> {/* ~20px height */}
  Link Text
</Link>

5. Accessibility Considerations

TYPESCRIPT
// ✅ GOOD: Indicate current page for screen readers
<Link
  href="/about"
  aria-current={isActive ? 'page' : undefined}
  className={isActive ? activeStyles : inactiveStyles}
>
  About
</Link>

// ✅ GOOD: Descriptive labels
<button aria-label="Open navigation menu">
  ☰
</button>

Key Takeaways

  • usePathname() - compare with href for active state
  • Exact vs partial match - exact for specific pages, partial for sections
  • Visual feedback - clear difference between active/inactive
  • Loading indicators - use useTransition() for navigation state
  • Nested navigation - highlight parent when on child route
  • Multiple variants - pills, underlines, sidebars
  • Mobile-friendly - large touch targets, clear states
  • Accessibility - aria-current for screen readers

What's Next?

You've mastered active links and navigation states! Next, we'll explore Redirects and Navigation Guards—how to protect routes, implement authentication checks, redirect users based on conditions, and build secure navigation flows.

You'll learn to control access to routes, redirect unauthenticated users, implement role-based access, and create robust authentication flows.

🎨 Design Consistency

Keep your active link styling consistent across your entire application. Pick one style (pills, underlines, backgrounds) and use it everywhere. Consistency helps users quickly understand where they are in your application!

Test Your Understanding

Question 1 of 4

How do you check if a link is active in Next.js?

Master active link styling and navigation states in Next.js! Build professional navigation UI.

Previous
usePathname and useSearchParams Hooks
Next
Redirects and Navigation Guards

Complete Navigation Mastery

Join 2,000+ developers building professional Next.js apps. Get the next lesson on redirects and navigation guards - 100% 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