What MDX Can Do

I switched this blog to MDX a while back, and I wanted to use this post to honestly document what MDX actually unlocks — not just as a developer curiosity, but as something that changes what writing a post can be.

I've seen a lot of MDX showcases, and most of them are just regular Markdown with a React button dropped in. What I wanted to explore was the genuinely distinct capabilities: things you structurally cannot do in plain .md, regardless of how clever your CSS is.

I landed on three.


1. Stateful Interactive Components

The most obvious capability: dropping a full client-side interactive experience directly into prose, with no page navigation.

Here's a personality quiz I built as a standalone component (TemperamentQuiz.astro) and embedded right here. It manages its own state — question progression, scoring, results — entirely in vanilla JS.

Four Temperaments Quiz

Discover your unique personality blend through the ancient wisdom of temperament theory

🌟

Sanguine

The Social Optimist

Choleric

The Natural Leader

🎨

Melancholic

The Thoughtful Perfectionist

🕊️

Phlegmatic

The Peaceful Mediator

This quiz consists of 30 questions designed to help you understand your temperament profile. Each question offers four choices that correspond to different temperament traits. Your results will show your primary and secondary temperaments along with detailed insights.

What makes this MDX and not just "a page with a widget" is that the component lives inside the writing. The prose before it sets the context; the prose after it can respond to what you just experienced. The reading and the doing are one continuous thing.


2. Props-Driven Components (MDX as a Data Format)

This is the capability I find most underrated. In MDX, you can pass structured data authored directly in the file into a component as props. The MDX file becomes both the narrative and the data source — no external JSON, no CMS field, no separate data file.

Here's a timeline of how my AI tooling stack has evolved, written entirely inside this .mdx file:

My AI Stack, 2023–2026

  1. Chat

    ChatGPT

    Started here like everyone else. Fun, occasionally useful, but not yet a workflow change.

  2. Self-hosted

    Open-WebUI + Local Models

    Spun up Open-WebUI on a local box to access both local models and the OpenAI API. R&D team adopted it first.

  3. Coding

    IDE Plugins (Cline, Continue, Roo Code)

    Started wiring AI into the editor. High friction, but the shape of things to come was clear.

  4. Coding

    Claude Code

    Game changer for frontend and backend teams. QA and mobile saw less benefit. Still the gold standard for agentic coding.

  5. Cost

    DeepSeek API + OpenCode

    Cost-effective personal stack. DeepSeek's quality-per-dollar made it the obvious pairing for personal projects.

  6. Self-hosted

    Nanobot on Raspberry Pi

    Runs locally, helps me manage the content calendar and draft ideas. Zero ongoing token cost.

  7. Current

    Google AI Pro (Gemini, Antigravity, Jules)

    Settled on this as my primary personal stack. $30/month, covers search, scheduled tasks, and agentic coding.

Notice that the data is right there in the .mdx file, sitting between the prose paragraphs. Someone with no code background could edit the dates, add a row, or change a description without touching a component file or a CMS. The component is just the renderer; the post is the source of truth.


3. Build-time Remark/Rehype Plugins

The third capability is invisible to the reader but structurally different from the first two: markdown syntax that gets transformed at build time by a plugin in the remark/rehype pipeline.

No component import. No explicit MDX syntax. Just a fenced code block with a language identifier — and a plugin that intercepts it during the build.

Here's a diagram of how a blog post moves from idea to published:

flowchart LR A[💡 Seed idea] --> B[Draft in content/drafts] B --> C{Ready?} C -- No --> D[Nanobot review] D --> B C -- Yes --> E[Move to content/blog] E --> F[Astro build] F --> G[Cloudflare Pages]

And here's the architecture of the three MDX capabilities in this very post:

flowchart TD MDX[MDX File] MDX -->|"import Component"| SC[Stateful Component\nTemperamentQuiz] MDX -->|"props authored in file"| PD[Props-Driven Component\nTimeline] MDX -->|"fenced code block"| RP[Rehype Plugin\nMermaid Diagram] SC -->|"client-side JS"| Browser PD -->|"server-rendered HTML"| Browser RP -->|"mermaid.js renders"| Browser

A fenced code block with the mermaid language tag is processed by a custom remark plugin I wrote for this site. At build time, it transforms the block into a <div class="mermaid"> element. Then on the client, mermaid.js picks it up and renders the SVG. Zero component imports in the MDX file — the syntax itself carries the semantic meaning.


Why This Matters

These three capabilities aren't just "cool features." Each one changes how you think about writing a post.

With component embedding, you're composing — dropping pre-built experiences into your prose. With props-driven data, you're owning the content directly, and the component just renders it. With rehype plugins, you're using familiar syntax that the build pipeline understands without any imports at all.

That's what MDX is actually about. Not widgets on a page, but a different way of thinking about what a post can be.