MDX Notes
The MDX errors you
MDX looks like Markdown but behaves like JSX. That gap is where most bugs live. Here are the mistakes you'll hit (or have already hit) and how to fix them fast.
Bookmark this page. You'll be back.
JSX Syntax Errors
MDX is strict about JSX. Things that are fine in plain Markdown will blow up here.
Mistake: Using HTML Comments
Why it breaks: MDX sees < and thinks you're starting a JSX element. <!-- --> isn't valid JSX.
Mistake: Unclosed HTML Tags
{/* ❌ Self-closing tags must use /> */}
<img src="/photo.png" alt="Photo">
<br>
<hr>
<input type="text">
{/* ✅ All tags must be closed in JSX */}
<img src="/photo.png" alt="Photo" />
<br />
<hr />
<input type="text" />Mistake: Using class Instead of className
{/* ❌ HTML attribute names don't work in JSX */}
<div class="container">Content</div>
<label for="input-name">Name</label>
{/* ✅ Use React's attribute names */}
<div className="container">Content</div>
<label htmlFor="input-name">Name</label>Mistake: Unescaped Special Characters
Curly braces and angle brackets have special meaning in MDX. You can't just type them raw.
{/* ❌ Curly braces are expressions in MDX */}
The object shape is {name: string, age: number}
{/* ✅ Escape or wrap in code */}
The object shape is `{name: string, age: number}`
{/* Or use expressions */}
The object shape is {'{name: string, age: number}'}
{/* ❌ Less-than signs start JSX elements */}
Use the comparison a < b to check values
{/* ✅ Use HTML entities or code formatting */}
Use the comparison `a < b` to check values
Use the comparison a < b to check valuesImport Issues
Imports trip people up more than you'd expect.
Mistake: Imports Not at the Top
# Introduction
Some introductory text.
{/* ❌ Import after content - may cause issues with some processors */}
import { Alert } from '../components/Alert';
<Alert>This might not work</Alert>
{/* ✅ Imports immediately after frontmatter */}
---
title: "My Page"
---
import { Alert } from '../components/Alert';
# Introduction
Some introductory text.
<Alert>This works correctly</Alert>Mistake: Incorrect Import Paths
{/* ❌ Common path errors */}
import { Button } from 'components/Button'; {/* Missing relative path */}
import { Button } from '../Components/Button'; {/* Case sensitivity */}
import { Button } from '../components/Button'; {/* Missing extension (sometimes) */}
{/* ✅ Correct imports */}
import { Button } from '../components/Button'; {/* Relative path */}
import { Button } from '../components/Button.jsx'; {/* With extension if needed */}
import { Button } from '@/components/Button'; {/* Path alias */}Mistake: Importing Non-Existent Exports
{/* Component file exports: export function Alert() {} */}
{/* ❌ Default import when it's a named export */}
import Alert from '../components/Alert';
{/* ✅ Named import matches the export */}
import { Alert } from '../components/Alert';
{/* ❌ Destructuring from default export */}
import { Alert } from '../components'; {/* If index.js doesn't re-export */}
{/* ✅ Check what the module actually exports */}
import { Alert } from '../components/Alert';Frontmatter Formatting Errors
YAML frontmatter is picky. One wrong indent and it's game over.
Mistake: Invalid YAML Syntax
{/* ❌ Indentation errors */}
---
title: "My Page"
description: "Indented too much"
---
{/* ❌ Missing quotes on special characters */}
---
title: MDX: The Complete Guide
description: Learn about "JSX" in Markdown
---
{/* ✅ Properly formatted YAML */}
---
title: "MDX: The Complete Guide"
description: 'Learn about "JSX" in Markdown'
tags:
- mdx
- tutorial
date: 2024-01-15
draft: false
---Mistake: Incorrect Data Types
---
# ❌ These will cause issues
date: 01-15-2024 # Ambiguous date format
order: "3" # String instead of number
tags: mdx, tutorial # Not a proper YAML array
draft: "true" # String instead of boolean
# ✅ Correct types
date: 2024-01-15 # ISO 8601 format
order: 3 # Number without quotes
tags: # Proper YAML array
- mdx
- tutorial
draft: true # Boolean without quotes
---Mistake: Missing Frontmatter Delimiters
{/* ❌ Only one set of dashes */}
---
title: "My Page"
# Content starts here
{/* ❌ Extra space before opening dashes */}
---
title: "My Page"
---
{/* ✅ Clean frontmatter delimiters */}
---
title: "My Page"
---
# Content starts hereComponent Prop Errors
These are sneaky because they often fail silently.
Mistake: String vs. Expression Props
Mistake: Children in Self-Closing Components
{/* ❌ Content won't render */}
<Alert type="warning" />
This text is NOT inside the Alert component.
It renders as normal paragraph text.
{/* ✅ Use opening and closing tags for children */}
<Alert type="warning">
This text IS inside the Alert component.
</Alert>Build Failures
MDX build errors can be cryptic. Here's what usually causes them.
Mistake: Mixing MDX Versions
{/* ❌ Conflicting MDX package versions */}
{
"dependencies": {
"@mdx-js/react": "^2.0.0",
"@mdx-js/mdx": "^3.0.0", /* Version mismatch! */
"@mdx-js/loader": "^1.6.0" /* Very old version! */
}
}
{/* ✅ Consistent versions */}
{
"dependencies": {
"@mdx-js/react": "^3.0.0",
"@mdx-js/mdx": "^3.0.0",
"@mdx-js/loader": "^3.0.0"
}
}Mistake: Missing Plugin Dependencies
// ❌ Using plugins without installing them
import remarkGfm from 'remark-gfm'; // Not in package.json!
import rehypeHighlight from 'rehype-highlight'; // Not installed!
// Fix: Install all plugins
// npm install remark-gfm rehype-highlightMistake: Incorrect Configuration
Missing Dependencies
# Common error: "Module not found: Can't resolve '@mdx-js/react'"
# ✅ Install all required MDX packages
npm install @mdx-js/react @mdx-js/mdx
# For Next.js
npm install @next/mdx @mdx-js/react @mdx-js/loader
# For Gatsby
npm install gatsby-plugin-mdx @mdx-js/react
# For Vite
npm install @mdx-js/rollup @mdx-js/reactIncorrect File Extensions
| - document.md | Won't process JSX (treated as plain Markdown) |
| - component.MDX | Case-sensitive file systems won't match .mdx |
| - page.mdx.js | Double extension confuses bundlers |
| - page.jsx | MDX syntax won't be processed |
| - document.mdx | Processed as MDX |
| - page.md | Processed as Markdown only (if configured) |
Hydration Errors
Hydration mismatches happen when the server renders one thing and the client renders something different. React panics.
Mistake: Browser-Only Code in MDX
{/* ❌ This causes hydration mismatch */}
<p>Current time: {new Date().toLocaleTimeString()}</p>
{/* Server renders one time, client renders another */}
{/* ❌ Accessing window/document directly */}
<p>Screen width: {window.innerWidth}px</p>
{/* ✅ Use client-only components */}
import { ClientOnly } from '../components/ClientOnly';
<ClientOnly>
<CurrentTime />
</ClientOnly>Mistake: Invalid HTML Nesting
{/* ❌ <p> cannot contain block elements — causes hydration error */}
<p>
<div>This is invalid HTML nesting</div>
</p>
{/* ❌ Paragraph wrapping in MDX can cause this silently */}
<p>
Some text
More text after blank line {/* This creates a nested <p> */}
</p>
{/* ✅ Use appropriate container elements */}
<div>
<p>First paragraph</p>
<p>Second paragraph</p>
</div>Whitespace Issues
MDX cares about whitespace in ways that will surprise you.
Mistake: Blank Lines Inside JSX
{/* ❌ Blank line creates paragraph break inside component */}
<Callout>
First line of callout.
This becomes a separate paragraph and may break the component.
</Callout>
{/* ✅ No blank lines, or the component handles it */}
<Callout>
First line of callout.
Second line continues.
</Callout>
{/* ✅ Or explicitly use paragraphs */}
<Callout>
<p>First paragraph.</p>
<p>Second paragraph.</p>
</Callout>Mistake: Indentation Causing Code Blocks
{/* ❌ 4-space indent creates unwanted code block */}
<details>
<summary>Click to expand</summary>
This text is indented 4 spaces and becomes a code block!
</details>
{/* ✅ Avoid 4-space indentation in content areas */}
<details>
<summary>Click to expand</summary>
This text has no extra indentation.
</details>Mistake: Missing Blank Lines Around Components
{/* ❌ Markdown won't parse without blank lines */}
Some paragraph text.
<Alert>Warning message</Alert>
More text continues here.
{/* ✅ Add blank lines around block-level components */}
Some paragraph text.
<Alert>Warning message</Alert>
More text continues here.Quick Troubleshooting Checklist
When something breaks, check these in order:
- Is the file extension
.mdx? Not.mdor.MDX - Are all tags closed? Every
<tag>needs</tag>or<tag /> - Are imports at the top? After frontmatter, before content
- Is frontmatter valid YAML? Check colons, quotes, indentation
- Are expressions in curly braces?
{variable}notvariable - Are special characters escaped?
<,{,}in text content - Are package versions compatible? All
@mdx-js/*same major version - Is configuration correct? Check framework-specific setup
- Are dependencies installed?
npm installafter adding packages - Is there a hydration mismatch? Check server vs. client rendering
Summary
Most MDX errors fall into a few buckets: JSX isn't HTML, imports are path-sensitive, YAML is indent-sensitive, and server/client rendering must match. Once you internalize these patterns, you'll spot the issue in seconds instead of debugging for an hour. When all else fails, paste your MDX into the MDX playground and see exactly where it chokes.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Common MDX Mistakes and Fixes.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this MDX Tutorial topic.
Search Terms
mdx-tutorial, mdx tutorial, mdx, tutorial, best, practices, common, mistakes
Related MDX Tutorial Topics