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