astro-markdown-mdx

Markdown and MDX in Astro

  • 5 min

Astro was born with content in mind. Unlike other frameworks where setting up a blog with Markdown requires installing plugins or parsers, in Astro, Markdown support is native.

Markdown is a lightweight markup language that is clean, portable, and doesn’t force us to write HTML tags just to add simple bold text.

You’re probably already used to using it, as it is widely used for writing documentation, blogs, and other types of content among developers and technical writers.

Furthermore, Astro goes a step further with MDX, which is an enhancement of Markdown to make it more dynamic (spoiler, it doesn’t work out very well, we’ll see why later).

If you want to learn more, check out the Markdown Course.

Standard Markdown (.md)

Astro has native support for Markdown, meaning if you place a Markdown file inside src/pages, it will automatically be converted into a web page.

src/pages/ └── blog/ ├── primer-post.md └── segundo-post.md

This will automatically generate the URLs /blog/primer-post and /blog/segundo-post.

Frankly, being able to create all content in Markdown is awesome 💛. This website you see is made that way. Almost all content is markdown + Astro.

Layouts in Markdown

The problem with a “raw” .md file is that when rendered, it only generates the HTML for the content (paragraphs, headings, lists). It doesn’t have <html>, <head>, or styles.

To solve this, Astro allows us to specify a Layout in the frontmatter of the Markdown file.

---
layout: ../../layouts/BlogLayout.astro
title: "My Journey Learning Astro"
author: "Luis Llamas"
date: "2023-10-20"
---

# Hello World

This is the content of my article. Astro will take all this text,
convert it to HTML, and inject it into the layout's `<slot />`.
Copied!

And in our BlogLayout.astro, we access that data through the frontmatter prop:

---
// src/layouts/BlogLayout.astro
const { frontmatter } = Astro.props;
---
<html>
  <head>
    <title>{frontmatter.title}</title>
  </head>
  <body>
    <h1>{frontmatter.title}</h1>
    <p class="meta">Written by {frontmatter.author}</p>
    
    <article class="prose">
      <slot /> </article>
  </body>
</html>
Copied!

Standard Markdown (.md) is perfect for purely textual content that doesn’t need interactivity. It’s fast to process and standard.

MDX: Markdown with JSX

MDX is an extension of Markdown syntax that allows us to write JSX (JavaScript XML) directly in our content files.

Basically: Markdown + Components = MDX.

Installation

Unlike standard Markdown, MDX is not enabled by default (although it’s official). We must add the integration.

npx astro add mdx
Copied!

This command will install the dependencies and update your astro.config.mjs.

Using components in MDX

Imagine you are writing a tutorial about array sorting and want to show an interactive component that visualizes the algorithm.

In a normal .md file, you would have to put a static image or a GIF. In an .mdx file, you can import and use the component.

Create a file src/pages/tutorial-sort.mdx:

---
layout: ../../layouts/TutorialLayout.astro
title: "Sorting Algorithms"
---
import VisualizadorSort from '../components/VisualizadorSort.jsx';
import Alerta from '../components/Alerta.astro';

# Introduction

The bubble sort method is simple but inefficient.

<Alerta tipo="info">
  This algorithm has a complexity of O(n²).
</Alerta>

Here you can see it in action:

<VisualizadorSort client:visible />

## Conclusion

As you could see in the component above...
Copied!

Exporting variables

In MDX you can also export variables from the content for the Layout to use, or even use them within the text itself.

---
title: "Hello MDX"
---
export const año = 2024;

# Welcome to the year {año}

Writing this from {frontmatter.title}.
Copied!

Key Differences

{ models: [ { name: “Markdown (.md)”, color: “#38bdf8” }, { name: “MDX (.mdx)”, color: “#FBBF24” } ], categories: { “Features”: [“Syntax”, “Components”, “Variables”], “Usage”: [“Learning Curve”, “Ideal Use”] }, specs: { “Syntax”: [“Strict standard”, “Markdown + JSX”], “Components”: [”❌ Not supported”, “✔️ Imports React”], “Variables”: [“Only frontmatter”, “Full JavaScript”], “Learning Curve”: [ { val: 20, max: 100, unit: ”%”, display: “Low” }, { val: 60, max: 100, unit: ”%”, display: “Medium” } ], “Ideal Use”: [“Blogs, Simple docs”, “Interactive apps”] } }

In my case, I don’t use MDX. The idea is very powerful, but for me it never worked very well:

  • It made things very very very slow (this website is very large)
  • It gave me more problems than it solved

But the best thing is for you to try it yourself. Maybe it will work for your project.