Creating Blog Tutorial Using Next.JS 15 & TailwindCSS 4.0 (Part #5)



This content originally appeared on DEV Community and was authored by gerry leo nugroho

Welcome back, blog architects! We’ve laid down our core layout components, setting a sleek foundation with a blurry navbar, multi-column footer, and tailored page layouts. Now, let’s amp up the UX with Navigation, Cards & Grids, and some Interactive Elements, channeling modern’s bold aesthetic—think responsive menus, animated cards, and engaging hover effects. We’re going wild with loads of creativity here, leveraging Next.js 15.x.x’s server-side magic and Tailwind CSS 4.x.x’s modern utilities, all while ensuring the code is digestible for newbies and SEO-optimized. Let’s dive into this vibrant continuation!

Navigation: Guiding Users with Style

Navigation is the compass of our blog—intuitive, responsive, and visually striking. We’ll craft a desktop menu with dropdowns, a mobile off-canvas menu, SEO-friendly breadcrumbs, and dynamic pagination.

src/components/DesktopMenu.tsx – Horizontal Menu with Dropdowns

"use client"; // Client-side for dropdown interactivity

import Link from "next/link";
import { useState } from "react";
import { FaChevronDown } from "react-icons/fa";

export default function DesktopMenu() {
  const [isDropdownOpen, setIsDropdownOpen] = useState(false); // Tracks dropdown state

  return (
    <nav>
      {/* Simple Links */}
      <Link href="/about">About</Link>
      <Link href="/blog">Blog</Link>

      {/* Dropdown Menu */}
      <div
        onMouseEnter={() => setIsDropdownOpen(true)}
        onMouseLeave={() => setIsDropdownOpen(false)}
      >
        Categories
        {isDropdownOpen && (
          <ul>
            <li>Tech</li>
            <li>Lifestyle</li>
            <li>Coding</li>
          </ul>
        )}
      </div>
      <Link href="/search">Search</Link>
    </nav>
  );
}

Why It’s Awesome

  • Dropdown: A hover-triggered menu with backdrop-blur-md for a glassy effect, fading in/out smoothly.
  • Hover Effects: Links scale up with hover:scale-105—a subtle nod to modern design’s interactivity.
  • Accessibility: ARIA attributes enhance screen reader support.

src/components/MobileMenu.tsx – Off-Canvas with Animations

Already integrated into BlurNavbar.tsx from the last section—its off-canvas design uses translate-y animations for a slick mobile experience.

src/components/Breadcrumbs.tsx – SEO-Friendly Navigation

import Link from "next/link";

type Crumb = { label: string; href: string };

export default function Breadcrumbs({ crumbs }: { crumbs: Crumb[] }) {
  return (
    <nav>
      <Link href="/">Home</Link>
      {crumbs.map((crumb, index) => (
        <span key={crumb.href}>
          /
          {index === crumbs.length - 1 ? (
            <span>{crumb.label}</span>
          ) : (
            <Link href={crumb.href}>{crumb.label}</Link>
          )}
        </span>
      ))}
    </nav>
  );
}

Usage Example

In src/app/blog/[slug]/page.tsx, add:

<Breadcrumbs
  crumbs={[
    { label: "Blog", href: "/blog" },
    { label: "Post Title", href: "/blog/post-title" },
  ]}
/>

Why It Shines

  • SEO: Links improve crawlability; the final crumb is text-only for current page semantics.
  • Responsive: Wraps gracefully on small screens.

src/components/Pagination.tsx – Dynamic Pagination

"use client";

import Link from "next/link";
import { usePathname, useSearchParams } from "next/navigation";

export default function Pagination({
  totalPages,
  basePath,
}: {
  totalPages: number;
  basePath: string;
}) {
  const pathname = usePathname();
  const searchParams = useSearchParams();
  const currentPage = Number(searchParams.get("page")) || 1;

  const pages = Array.from({ length: totalPages }, (_, i) => i + 1);

  return (
    <div>
      {pages.map((page) => (
        <Link
          key={page}
          href={`${pathname}?page=${page}`}
          className={currentPage === page ? "active" : ""}
        >
          {page}
        </Link>
      ))}
    </div>
  );
}

Usage Example

In src/app/blog/page.tsx, add:

<Pagination totalPages={10} basePath="/blog" />

Why It’s Great

  • Dynamic: Uses Next.js’s useSearchParams for page tracking.
  • Styling: Rounded buttons with hover transitions aligned with modern web design polish.

Cards & Grids: Visual Storytelling

Cards are the heartbeat of our blog’s content—responsive, interactive, and eye-catching.

src/components/PostCard.tsx – Enhanced from Last Section

Updated with more flair:

import Link from "next/link";
import Image from "next/image";

type Post = {
  slug: string;
  frontmatter: {
    title: string;
    description: string;
    imageOg?: string;
    category: string;
  };
};

export default function PostCard({
  post,
  variant = "grid",
}: {
  post: Post;
  variant?: "grid" | "list";
}) {
  return (
    <div>
      {/* Image with Hover Zoom */}
      {post.frontmatter.imageOg && (
        <Image
          src={post.frontmatter.imageOg}
          alt={post.frontmatter.title}
          width={300}
          height={200}
          className="hover:scale-105 transition-transform"
        />
      )}

      {/* Content */}
      <div>
        <span>{post.frontmatter.category}</span>
        <h3>{post.frontmatter.title}</h3>
        <p>{post.frontmatter.description}</p>
      </div>
    </div>
  );
}

What’s New?

  • Category Badge: A rounded tag adds visual hierarchy.
  • Hover Effects: Card lifts with hover:shadow-xl and image zooms—pure modern design’s energy.
  • Responsive Images: sizes attribute optimizes image loading.

src/components/CategoryCard.tsx – Category Highlights

import Link from "next/link";

export default function CategoryCard({
  category,
  count,
}: {
  category: string;
  count: number;
}) {
  return (
    <div>
      {/* Overlay Effect */}
      <div>
        <span>{category}</span>
        <span>{count} Posts</span>
      </div>
    </div>
  );
}

Usage Example

In src/app/page.tsx’s trending section:

<CategoryCard category="Tech" count={15} />

Why It Pops

  • Gradient: A bold background with a hover overlay adds depth.
  • Relative Positioning: Ensures text stays above the overlay.

src/components/AuthorCard.tsx – Author Spotlight

import Image from "next/image";
import { FaTwitter, FaLinkedin } from "react-icons/fa";

export default function AuthorCard({
  name,
  bio,
  avatar,
  twitter,
  linkedin,
}: {
  name: string;
  bio: string;
  avatar: string;
  twitter?: string;
  linkedin?: string;
}) {
  return (
    <div>
      <Image src={avatar} alt={name} width={100} height={100} />
      <h3>{name}</h3>
      <p>{bio}</p>
      {twitter && <a href={twitter}><FaTwitter /></a>}
      {linkedin && <a href={linkedin}><FaLinkedin /></a>}
    </div>
  );
}

Why It Works

  • Compact: A clean layout for author bios, with social icons for engagement.
  • Dark Mode: Tailwind’s dark: classes ensure readability.

Interactive Elements: Engaging Users

Let’s add some interactivity with hover effects and reusable components.

src/components/HoverImage.tsx – Image with Zoom

import Image from "next/image";

export default function HoverImage({
  src,
  alt,
  width,
  height,
}: {
  src: string;
  alt: string;
  width: number;
  height: number;
}) {
  return (
    <div className="group">
      <Image
        src={src}
        alt={alt}
        width={width}
        height={height}
        className="group-hover:scale-110 transition-transform"
        loading="lazy"
      />
    </div>
  );
}

Why It’s Engaging

  • Zoom: group-hover:scale-110 creates a subtle, inviting effect.
  • Lazy Loading: Native loading="lazy" boosts performance.

src/components/Tooltip.tsx – Contextual Info

"use client";

import { useState } from "react";

export default function Tooltip({
  content,
  children,
}: {
  content: string;
  children: React.ReactNode;
}) {
  const [isVisible, setIsVisible] = useState(false);

  return (
    <div
      onMouseEnter={() => setIsVisible(true)}
      onMouseLeave={() => setIsVisible(false)}
    >
      {children}
      {isVisible && <span>{content}</span>}
    </div>
  );
}

Usage Example

<Tooltip content="This is a tooltip">
  <button>Click here</button>
</Tooltip>

Why It’s Handy

  • Simple: A hover-triggered tooltip with Tailwind styling.
  • Accessible: Naturally works with mouse and touch (though keyboard support could be added).

To Be Continued

We’ve tackled Navigation, Cards & Grids, and started Interactive Elements—all with modern-design-inspired flair, responsive design, and SEO-friendly code. This is part two of a multi-part journey due to the epic scope you’ve set!


This content originally appeared on DEV Community and was authored by gerry leo nugroho