Unlocking MDX Superpowers in Astro
Combine markdown simplicity with dynamic UI components, custom embedded widgets, and interactive elements using MDX.
Listen to Article
PlayingClick play to listen to audio narration

Table of Contents
MDX allows developers to directly import and render dynamic UI components directly inside standard Markdown documents.
Why Use MDX?
Standard Markdown is great for static text, but MDX elevates content by enabling:
- Embedded interactive charts and widgets.
- Callout banners and custom alerts.
- Live code playgrounds and interactive demos.
Importing UI Components in MDX
In an .mdx file, simply import your React, Vue, Svelte, or Astro components:
import Counter from '../../components/Counter.jsx';
# Welcome to My Interactive Post
Below is a live interactive component embedded directly within MDX content:
<Counter client:visible />
Customizing MDX Components with components Prop
Override standard HTML tags (<h1>, <blockquote>, <pre>) globally or per page to render custom styled components effortlessly.
What is MDX?
MDX is Markdown extended with JSX. It lets you import and use interactive components directly inside your content files, while keeping the authoring experience of plain Markdown.
---
title: My Post
---
import Chart from '../components/Chart.astro';
import Callout from '../components/Callout.astro';
## Data Trends
<Chart data={[10, 24, 18, 42]} />
<Callout type="warning">
This data covers Q1 2026 only.
</Callout>
Regular **Markdown** still works alongside components.
Setting Up MDX in Astro
npx astro add mdx
This installs @astrojs/mdx and updates astro.config.mjs automatically:
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
export default defineConfig({
integrations: [mdx()],
});
Rename any .md content file to .mdx to enable MDX features.
Importing Components into MDX
You can import Astro components, React components, or any UI framework component that Astro supports:
import Tabs from '../../components/Tabs.astro';
import CodeExample from '../../components/CodeExample.jsx';
## Installation Options
<Tabs>
<Fragment slot="npm">npm install my-package</Fragment>
<Fragment slot="pnpm">pnpm add my-package</Fragment>
</Tabs>
Passing Props to Components
MDX components receive props the same way as in JSX:
import Alert from '../../components/Alert.astro';
<Alert type="info" title="Did you know?">
Astro ships zero JavaScript by default.
</Alert>
---
// Alert.astro
const { type = 'info', title } = Astro.props;
---
<div class={`alert alert-${type}`}>
<strong>{title}</strong>
<slot />
</div>
Global MDX Components
Avoid importing the same component in every MDX file by registering it globally in astro.config.mjs:
import mdx from '@astrojs/mdx';
import Callout from './src/components/Callout.astro';
export default defineConfig({
integrations: [
mdx({
components: {
// Override default blockquote with a custom Callout
blockquote: Callout,
},
}),
],
});
Now every > blockquote in every MDX file renders as your Callout component.
Syntax Highlighting with Shiki
Astro uses Shiki for syntax highlighting out of the box. Configure your theme in astro.config.mjs:
export default defineConfig({
markdown: {
shikiConfig: {
theme: 'github-dark',
langs: [],
wrap: true,
},
},
});
Always include a language identifier on your fenced code blocks for accurate highlighting:
```typescript
const greet = (name: string): string => `Hello, ${name}!`;
## When to Use MDX vs Plain Markdown
| Use Markdown when... | Use MDX when... |
|:---|:---|
| Pure prose content | Content needs interactive components |
| Simple blog posts | Embedded demos or charts |
| Documentation text | Custom callout/alert boxes |
| No component imports needed | Tabbed code examples |Written by Editorial Team
Tech contributor covering software architecture, AI research, cloud infrastructure, and systems engineering practices.