Building an Interactive Blog with MDX, Next.js & Custom Components
A deep dive into creating rich, interactive blog posts using MDX with custom React components, code highlighting, mermaid diagrams, and more — all inside a Next.js portfolio.
Why MDX?
MDX lets you write JSX inside Markdown — meaning your blog posts can contain interactive React components alongside regular prose. This post demonstrates every feature available in this blog system.
Text Formatting
Standard markdown formatting works perfectly:
- Bold text for emphasis
- Italic text for subtle highlights
Strikethroughfor correctionsinline codefor technical terms- External links open in new tabs
- Internal links stay within the site
Blockquotes are great for calling out important information or citing sources. They render with a distinctive left border and muted background.
Code Blocks
Syntax-highlighted code blocks with language detection:
TypeScript
interface BlogPost {
title: string;
description: string;
tags: string[];
createdAt: Date;
content: string;
}
async function getPost(slug: string): Promise<BlogPost> {
const file = await import(`@/features/blog/content/${slug}.mdx`);
return {
...file.metadata,
content: file.default,
};
}React Component
"use client";
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount((c) => c + 1)}>
Clicked {count} times
</button>
);
}Shell Commands
# Create a new Next.js project with TypeScript
npx create-next-app@latest my-portfolio --typescript --tailwind --app
# Install MDX support
npm install @next/mdx next-mdx-remote gray-matter
# Start the dev server
npm run devCSS
/* Modern glassmorphism card */
.glass-card {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 16px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}Tables
Markdown tables render with proper styling:
| Technology | Purpose | Why We Chose It |
|---|---|---|
| Next.js 16 | Framework | App Router, RSC, Turbopack |
| TypeScript | Type Safety | Catch bugs at compile time |
| Tailwind CSS v4 | Styling | Utility-first, zero runtime |
| MDX | Content | React components in Markdown |
| Framer Motion | Animation | Declarative, performant |
| shadcn/ui | Components | Accessible, customizable |
Mermaid Diagrams
Mermaid diagrams render inline — perfect for architecture docs and flowcharts:
Architecture Overview
Blog Post Lifecycle
Lists
Ordered List
- Plan your content structure
- Write MDX with frontmatter metadata
- Add custom components where needed
- Preview locally with hot reload
- Deploy — content updates instantly
Unordered List with Nesting
- Frontend
- React Server Components for static content
- Client Components for interactivity
- Streaming for progressive loading
- Content Pipeline
- MDX parsing with
next-mdx-remote - Frontmatter extraction with
gray-matter - Rehype plugins for syntax highlighting
- MDX parsing with
- Deployment
- Vercel for hosting
- Edge Functions for API routes
- ISR for incremental updates
Custom MDX Components
The following sections demonstrate custom React components that are available in all blog and project pages.
WorkInProgress Banner
Use this to mark sections that are still being developed:
Work in progress
I'm still working on this section. Check back soon for updates!
Dropdown Component
Interactive dropdowns for collapsible content — great for FAQs, detailed explanations, or optional reading:
Images
Standard markdown images work with Next.js optimization:

Math & Formulas
Inline mathematical expressions using Unicode:
The deflection of a cantilever beam is given by: y = (F/EI)(Lx²/2 − x³/6)
Where:
- F = Applied force (Newtons)
- E = Young's modulus (Pa)
- I = Moment of inertia (m⁴)
- L = Beam length (m)
- x = Position along the beam
Horizontal Rules & Spacing
Use --- to create visual section breaks (like the ones throughout this post).
Heading Hierarchy
This post demonstrates all heading levels:
H1 — Page Title (used once)
H2 — Major Section
H3 — Subsection
H4 — Detail Section
Best Practices for MDX Blog Posts
| Practice | Why |
|---|---|
| Use frontmatter | SEO, sorting, filtering |
Add description | Appears in previews & OG tags |
| Tag appropriately | Enables topic-based browsing |
| Use custom components | Enrich static content |
| Keep images optimized | Next.js Image handles this |
| Test in dev mode | Hot reload catches errors fast |
What's Next?
Work in progress
I'm still working on this section. Check back soon for updates!
This blog system is actively evolving. Upcoming features include:
- 🔍 Full-text search across all posts
- 📊 Reading time estimation in post cards
- 💬 Comment system with GitHub Discussions
- 📧 Newsletter integration for new post alerts
- 🏷️ Category pages for topic-based browsing
Stay tuned for updates — and feel free to explore the source code to see how everything works under the hood!
