Building Reusable Blog Components in Next.js
Stop repeating your UI code. Learn to build reusable React components, manage props, and structure your project for long-term maintainability.
Previously in this course, we explored handling 404 Not Found pages to ensure our users have a graceful experience when navigation goes wrong. Now that our core routing is stable, it's time to clean up our templates. In this lesson, we’ll move beyond monolithic page files and learn how to extract repetitive UI into reusable components.
Why We Need Component-Driven Development
As you build your blog, you'll notice you’re writing the same HTML structure for every post "card" on your homepage. If you decide to change the border radius or the font size of the title, you’ll have to hunt through every page file to update it.
This is the primary reason for refactoring your UI into standalone components. By encapsulating logic and structure, you create a "single source of truth" for your design. When you need a change, you update it in one file, and the entire app reflects that change instantly.
Setting Up the Components Folder
In a standard Next.js project, there is no strict rule on where to put your files, but the convention for a scalable architecture is to create a top-level components/ directory.
- Create a folder named
componentsin your project root (at the same level asapp/). - Inside, create a folder for your shared UI, like
components/blog-card. - Create a file named
BlogCard.tsxinside that folder.
This structure keeps your app/ directory focused strictly on routing and server-side logic, while components/ holds your UI primitives.
Building a Reusable Blog Card
To make a component reusable, we need to pass data into it dynamically. We do this using props (short for properties). Think of props as the arguments you pass to a function; they define how the component behaves and what it displays.
Let’s build our BlogCard to accept a title, a brief excerpt, and a link:
TSX// components/blog-card/BlogCard.tsx import Link from CE9178">'next/link'; interface BlogCardProps { title: string; excerpt: string; slug: string; } export default function BlogCard({ title, excerpt, slug }: BlogCardProps) { return ( <article className="p-6 border border-gray-200 rounded-lg shadow-sm hover:shadow-md transition"> <h2 className="text-xl font-bold mb-2">{title}</h2> <p className="text-gray-600 mb-4">{excerpt}</p> <Link href={CE9178">`/blog/${slug}`} className="text-blue-600 font-medium"> Read more → </Link> </article> ); }
By defining an interface (or a type), we ensure that anyone using this component must provide the necessary data. This is a massive win for team collaboration and bug prevention.
Using the Component in Your Homepage
Now, instead of hardcoding HTML in your page.tsx, you simply import your new component. This is the essence of refactoring monolithic components to improve code quality.
TSX// app/page.tsx import BlogCard from CE9178">'@/components/blog-card/BlogCard'; export default function HomePage() { const posts = [ { title: "Learning Next.js", excerpt: "It's easier than you think!", slug: "learning-nextjs" }, { title: "CSS Tips", excerpt: "Mastering Tailwind...", slug: "css-tips" }, ]; return ( <main className="grid gap-6 p-8"> {posts.map((post) => ( <BlogCard key={post.slug} title={post.title} excerpt={post.excerpt} slug={post.slug} /> ))} </main> ); }
Hands-on Exercise
- Create the component: Follow the steps above to create your
BlogCard.tsxfile. - Refactor: Find the section on your homepage where you previously hand-coded your blog previews.
- Map: Use the
.map()method (as shown above) to render yourBlogCardcomponents dynamically based on an array of post data. - Test: Ensure the links still work and that all cards render correctly with their unique titles.
Common Pitfalls
- Prop Drilling: Don't pass data through five layers of components if you don't have to. Keep components small, but don't over-engineer abstractions too early.
- The "Any" Trap: Avoid using
anyin your TypeScript prop interfaces. Always define exactly what the component expects to receive. - Missing Keys: When rendering components in a list using
.map(), always include a uniquekeyprop. Next.js uses this to track which items have changed or moved.
Frequently Asked Questions
Q: Should every small piece of UI be a component? A: Not necessarily. If a block of code is only used in one place and isn't complex, keep it in the page file. Focus on extracting elements that repeat across multiple pages.
Q: Can I use server components for these cards?
A: Yes! Since BlogCard doesn't require state (like useState) or browser events (like onClick), it is a perfect candidate for a Server Component by default.
Q: How do I handle optional props?
A: Use a question mark in your interface: subtitle?: string. This makes the prop optional, allowing the component to render even if that data isn't provided.
Recap
We’ve learned that building components with props is the key to maintaining a clean codebase. By extracting your blog cards, you've taken a significant step toward a truly modular, professional-grade application. Remember, good reusable React components act as a contract: they promise to display data in a consistent way, making your entire application more predictable.
Up next: We'll start making our blog interactive by learning how to handle form submissions using Server Actions.
Work with me

Next.js Full-Stack Web App Development
A fast, SEO-ready full-stack web app built with Next.js 16 — from idea to deployed product, by an engineer who ships to production.

Next.js E-commerce Store Development
Turn your Facebook page or small shop into a real online store — fast, mobile-first, and built to sell. Own your storefront, not just a social page.


