Writing MDX Blog Posts: A Complete Guide
Learn how to create rich, interactive blog posts using MDX - combining the simplicity of Markdown with the power of React components.
Introduction
MDX is a powerful format that combines the simplicity of Markdown with the flexibility of React components. This guide will show you how to create engaging, interactive blog posts using MDX.
What is MDX?
MDX allows you to write JSX directly in your Markdown files. This means you can:
- Use React components within your content
- Create interactive elements
- Maintain the readability of Markdown
- Add rich media and custom styling
Front Matter Structure
Every MDX blog post starts with YAML front matter that defines metadata:
---
title: "Your Post Title"
excerpt: "Brief description of your post"
publishedAt: "2025-12-16T21:00:00Z"
updatedAt: "2025-12-16T21:00:00Z"
tags: ["tag1", "tag2", "tag3"]
featured: true
interactive: true
components: ["ComponentName1", "ComponentName2"]
author:
name: "Your Name"
email: "your.email@example.com"
bio: "Your bio"
seo:
title: "SEO Title"
description: "SEO Description"
keywords: ["keyword1", "keyword2"]
ogImage: "/images/og-image.jpg"
---
Key Fields Explained
title: The main title of your postexcerpt: A brief summary shown in post listingspublishedAt: Publication date in ISO formattags: Array of tags for categorizationfeatured: Boolean to highlight important postsinteractive: Set totrueif using React componentscomponents: List of custom components used in the postseo: Optional SEO overrides for better search visibility
Basic Markdown Syntax
MDX supports all standard Markdown syntax:
Headings
# H1 Heading
## H2 Heading
### H3 Heading
#### H4 Heading
##### H5 Heading
###### H6 Heading
Text Formatting
- Bold text using
**bold** - Italic text using
*italic* Strikethroughusing~~strikethrough~~Inline codeusing backticks
Lists
Unordered lists:
- Item 1
- Item 2
- Nested item
- Another nested item
Ordered lists:
- First item
- Second item
- Third item
Links and Images
[Link text](https://example.com)

Code Blocks
Use triple backticks with language specification:
function greet(name) {
return `Hello, ${name}!`;
}
console.log(greet("World"));
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10))
Blockquotes
This is a blockquote. It can span multiple lines and is great for highlighting important information or quotes from other sources.
Tables
| Feature | Markdown | MDX |
|---|---|---|
| Headers | ✅ | ✅ |
| Lists | ✅ | ✅ |
| Code | ✅ | ✅ |
| Components | ❌ | ✅ |
| Interactive | ❌ | ✅ |
MDX-Specific Features
Using React Components
MDX allows you to use React components directly in your content. The blog system provides several built-in components:
Custom Images
Instead of regular Markdown images, you can use the enhanced image component:
<CustomImage
src="/images/example.jpg"
alt="Example image"
width={800}
height={400}
caption="This is an example image with optimization"
/>
Custom Links
Enhanced links with better styling and external link handling:
<CustomLink href="https://example.com" external>
Visit Example.com
</CustomLink>
Code Blocks with Syntax Highlighting
<CodeBlock language="typescript" title="example.ts">
{`interface BlogPost {
title: string;
content: string;
publishedAt: Date;
}`}
</CodeBlock>
YouTube Videos
🎥 But what is a neural network? | Deep learning chapter 1
Embed YouTube videos easily with the YouTube component:
<YouTube
id="dQw4w9WgXcQ"
title="Rick Astley - Never Gonna Give You Up"
/>
Different sizes:
<YouTube id="dQw4w9WgXcQ" size="small" />
<YouTube id="dQw4w9WgXcQ" size="medium" />
<YouTube id="dQw4w9WgXcQ" size="large" />
<YouTube id="dQw4w9WgXcQ" size="full" />
Advanced options:
<YouTube
id="dQw4w9WgXcQ"
title="Custom Title"
size="large"
start={30}
end={120}
autoplay={false}
controls={true}
/>
Or use a full YouTube URL:
<YouTubeUrl
url="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
title="Video from URL"
size="large"
/>
Interactive Elements
You can create interactive content using React components:
<div className="bg-pine-50 dark:bg-pine-900 p-6 rounded-lg border border-pine-200 dark:border-pine-700">
<h4 className="text-pine-800 dark:text-pine-200 font-semibold mb-2">
💡 Pro Tip
</h4>
<p className="text-pine-700 dark:text-pine-300">
Use interactive elements sparingly to enhance your content without overwhelming readers.
</p>
</div>
JavaScript Sandbox (Full JavaScript Support)
For complete JavaScript freedom, use the JavaScriptSandbox component:
Interactive Vector Field Animation
Interactive Vector Field - Move your mouse around!
Simple Calculator Example
Interactive Calculator
HTML
<div class="calculator">
<input type="number" id="num1" placeholder="First number">
<select id="operation">
<option value="+">+</option>
<option value="-">-</option>
<option value="*">×</option>
<option value="/">/</option>
</select>
<input type="number" id="num2" placeholder="Second number">
<button onclick="calculate()">Calculate</button>
<div id="result">Enter numbers and click Calculate</div>
</div>
CSS
.calculator {
display: flex;
flex-direction: column;
gap: 10px;
max-width: 300px;
margin: 0 auto;
padding: 20px;
}
.calculator input, .calculator select, .calculator button {
padding: 10px;
border: 2px solid #234F1E;
border-radius: 6px;
font-size: 16px;
}
.calculator button {
background: #234F1E;
color: white;
cursor: pointer;
font-weight: bold;
}
.calculator button:hover {
background: #1a3d17;
}
#result {
font-size: 18px;
font-weight: bold;
color: #234F1E;
text-align: center;
padding: 15px;
background: #f0f8f0;
border-radius: 6px;
border: 2px solid #e0f0e0;
min-height: 20px;
}
JavaScript
function calculate() {
const num1 = parseFloat(document.getElementById('num1').value);
const num2 = parseFloat(document.getElementById('num2').value);
const operation = document.getElementById('operation').value;
if (isNaN(num1) || isNaN(num2)) {
document.getElementById('result').textContent = 'Please enter valid numbers';
return;
}
let result;
switch(operation) {
case '+': result = num1 + num2; break;
case '-': result = num1 - num2; break;
case '*': result = num1 * num2; break;
case '/': result = num2 !== 0 ? num1 / num2 : 'Cannot divide by zero'; break;
}
document.getElementById('result').textContent = 'Result: ' + result;
}
// Add some interactivity
document.addEventListener('DOMContentLoaded', function() {
const inputs = document.querySelectorAll('input');
inputs.forEach(input => {
input.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
calculate();
}
});
});
});
Best Practices
1. Structure Your Content
- Use clear headings to organize your content
- Keep paragraphs concise and focused
- Use lists to break down complex information
- Include a table of contents for longer posts
2. Optimize for Readability
- Write in a conversational tone
- Use short sentences and paragraphs
- Include plenty of white space
- Add relevant images and code examples
3. SEO Considerations
- Write descriptive titles and excerpts
- Use relevant tags consistently
- Include alt text for all images
- Optimize your front matter SEO fields
4. Interactive Elements
- Use components to enhance, not replace, good writing
- Ensure interactive elements are accessible
- Test components on different screen sizes
- Keep loading times in mind
5. Code Examples
- Always specify the language for syntax highlighting
- Include complete, runnable examples when possible
- Add comments to explain complex code
- Use consistent formatting and indentation
File Naming and Organization
File Naming Convention
Use the format: YYYY-MM-DD-post-slug.mdx
Examples:
2025-12-16-mdx-blog-guide.mdx2025-12-15-react-hooks-tutorial.mdx2025-12-14-machine-learning-basics.mdx
Directory Structure
blog-content/
├── posts/
│ ├── 2025-12-16-mdx-blog-guide.mdx
│ ├── 2025-12-15-react-tutorial.mdx
│ └── 2025-12-14-ml-basics.mdx
├── images/
│ ├── post-images/
│ └── thumbnails/
└── README.md
Publishing Workflow
- Create your MDX file with proper front matter
- Write your content using Markdown and MDX syntax
- Add images to the images directory if needed
- Test locally if you have a development setup
- Commit and push to your blog repository
- Wait for deployment (automatic via ISR)
Common Pitfalls to Avoid
1. Invalid Front Matter
# ❌ Wrong - missing quotes around date
publishedAt: 2025-12-16T21:00:00Z
# ✅ Correct - properly quoted
publishedAt: "2025-12-16T21:00:00Z"
2. Mixing Markdown and JSX Incorrectly
<!-- ❌ Wrong - mixing syntax -->
**Bold text** <strong>and JSX</strong>
<!-- ✅ Correct - consistent syntax -->
**Bold text** and **more bold text**
3. Missing Component Imports
If you use custom components, make sure they're available in the MDX component library.
4. Accessibility Issues
Always include:
- Alt text for images
- Proper heading hierarchy
- Descriptive link text
- Keyboard navigation support
Advanced Tips
1. Custom Styling
You can use Tailwind CSS classes directly in your MDX:
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 my-8">
<div className="bg-white dark:bg-gray-800 p-6 rounded-lg shadow">
<h3>Column 1</h3>
<p>Content for the first column.</p>
</div>
<div className="bg-white dark:bg-gray-800 p-6 rounded-lg shadow">
<h3>Column 2</h3>
<p>Content for the second column.</p>
</div>
</div>
2. Conditional Content
You can use JavaScript expressions in MDX:
{process.env.NODE_ENV === 'development' && (
<div className="bg-yellow-100 border border-yellow-400 text-yellow-700 px-4 py-3 rounded">
This content only shows in development mode.
</div>
)}
3. Dynamic Content
<div>
<p>This post was last updated: {new Date().toLocaleDateString()}</p>
</div>
Conclusion
MDX provides a powerful way to create rich, interactive blog content while maintaining the simplicity of Markdown. By following these guidelines and best practices, you can create engaging posts that provide value to your readers.
Remember to:
- Start with good content and clear structure
- Use interactive elements to enhance, not distract
- Optimize for both readers and search engines
- Test your posts across different devices and browsers
Happy blogging with MDX! 🚀
This guide covers the essentials of writing MDX blog posts. For more advanced topics or specific questions, feel free to explore the documentation or reach out with questions.