Astro MDX — Markdown with Interactive Components
Learn how to use MDX in Astro: embed React, Vue, or Svelte components inside Markdown content with type-safe frontmatter validation.
In this lesson, you'll configure MDX support in Astro, write .mdx files that import and use interactive components, and combine rich Markdown content with dynamic UI elements.
What You'll Learn
How to install and configure @astrojs/mdx, write MDX files with embedded components, and use frontmatter with type-safe schemas.
Why It Matters
MDX lets content authors write in familiar Markdown while adding interactive components where needed—without switching to a different page type or framework.
Real-World Use
DodaTech's advanced tutorials use MDX to embed interactive code sandboxes and live examples directly in Markdown content.
flowchart LR
A[.mdx File] --> B[Markdown Content]
A --> C[Component Imports]
B --> D[HTML Output]
C --> E[Interactive Islands]
style A fill:#ff5a03,color:#fff
Setup MDX
Install the MDX integration:
npx astro add mdx
This adds @astrojs/mdx to your astro.config.mjs:
import { defineConfig } from "astro/config";
import mdx from "@astrojs/mdx";
export default defineConfig({
integrations: [mdx()],
});
Writing MDX
Create src/pages/blog/hello-world.mdx:
---
title: Hello World
description: "My first MDX post with rich content."
---
## Introduction
This is a regular Markdown paragraph with **bold** and _italic_ text.
- List item one
- List item two
Output: The MDX file renders as a page at /blog/hello-world/ with the Markdown converted to HTML.
Using Components in MDX
Import and use framework components directly:
---
title: Interactive Demo
description: "A tutorial page with embedded interactive components."
---
import Counter from "../../components/Counter.tsx";
import Chart from "../../components/Chart.vue";
## Live Counter
Click the button to increment:
<Counter client:load />
## Data Visualization
This chart updates with real data:
<Chart client:visible />
Output: The <Counter> and <Chart> components become interactive islands within the Markdown content. Everything else renders as static HTML.
Custom Components for MDX
Define a map of components to replace HTML elements:
// src/components/mdx-components.js
import CodeBlock from "../components/CodeBlock.astro";
import Note from "../components/Note.astro";
export function useMDXComponents() {
return {
pre: CodeBlock,
blockquote: Note,
};
}
Configure in your layout:
---
import { useMDXComponents } from "../components/mdx-components";
---
<article>
<slot />
</article>
Now code blocks and blockquotes in MDX use your custom components automatically.
Type-Safe Frontmatter
Validate MDX frontmatter using content collections:
// src/content/config.ts
import { defineCollection, z } from "astro:content";
const blogCollection = defineCollection({
schema: z.object({
title: z.string(),
description: z.string().max(165),
date: z.date(),
tags: z.array(z.string()).optional(),
}),
});
export const collections = {
blog: blogCollection,
};
Common Mistakes
- Forgetting the
client:*directive on MDX components: Framework components in MDX needclient:*to be interactive, just like in.astropages. - Not configuring the MDX integration: Without
@astrojs/mdxin config,.mdxfiles throw build errors. - Using
.mdxfor pages without components: If a page has no interactive components, use.mdinstead. It's simpler and builds faster. - Missing imports for components: Every component used in MDX must be imported at the top of the file.
- Putting server logic in MDX: MDX doesn't support the
---frontmatter fence for server code. Use.astropages for dynamic logic.
Practice Questions
What makes MDX different from regular Markdown? Answer: MDX allows importing and using JavaScript/TypeScript components directly in Markdown content.
How do you install MDX support in Astro? Answer: Run
npx astro add mdx. It installs@astrojs/mdxand updatesastro.config.mjs.Can MDX files use content collection schemas? Answer: Yes. MDX files in
src/content/validate against collection schemas, just like.mdfiles.What happens if you use a component without a
client:*directive in MDX? Answer: The component renders as static HTML with no interactivity. It appears but doesn't respond to user input.
Challenge
Create an MDX page that imports a React counter component with client:load, a Vue chart with client:visible, and a note callout component. Add custom MDX component mapping for blockquotes.
Mini Project
Build a tutorial page using MDX for a "Getting Started" guide. Include a live code sandbox component, an interactive tip calculator, and a downloadable code snippet component.
FAQ
What's Next
Learn about Astro Content Collections for type-safe management of Markdown and MDX content at scale.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro