“Heap, Heap, Array!”

MDX: The good, the bad, and the ugly

If you have your own blog and like the simplicity of Markdown, but don’t want to give up JSX, you may want to give MDX a try.

The Good, The Bad, and the Ugly – TikTok edition
MDX is pretty good – even with the bad and ugly parts

MDX is a new authorable format that aims to combine the simplicity of Markdown with the power of JSX by letting you use React components in Markdown documents. In my previous post I already briefly touched upon the use of MDX on this website and implied that MDX isn’t quite ready for prime time yet. In this post I’ll tell you more about what MDX does, and what’s good and not so good about it.

The good

React lets you define components that you can easily reuse throughout your application or website. At some point, you will inevitably want to reuse some of them within your content as well. This is where MDX comes in.

For instance, you might have elements that you currently mark up using custom span elements with hard to remember classes:

Moreover, the CSS for this component is likely defined in some global stylesheet. To avoid issues with specificity, you probably use a methodology like BEM.

By converting this span into a React component, we can use it as if it were simply a native, styled HTML element without having to worry about CSS scopes:

This is much cleaner and easier to remember!

MDX gets even more interesting when you need interactive components.

I don’t have any yet on my website, but Docusaurus has a pretty good example of an interactive component that you may want to add to an otherwise completely static page. It comes with a Tabs component, which can show different code snippets for users of different platforms:

From an author’s perspective, there is very little difference between this interactive Tabs and our static Img component. Both are just as easy to use!

The bad

If your website currently uses plain Markdown, a move to MDX will likely result in increased technical complexity and “lock-in”.


Markdown is simple. You write your content and feed it to some function, which returns some HTML that can be rendered in a view.

MDX is… less simple. You still write your content and you’ll still use some functions to convert it. However, the output now also includes styling and executable code, which you need to pass around and serialise properly. It’s also less clear what and when changes should trigger updates to pages.

Fortunately the frameworks and libraries handhold you through the process very well, so in practice you don’t ever need to think about it – but you will find that unless you are willing to dig into the internals, you will have less freedom to do things exactly the way you want.


Another thing to keep in mind is that Markdown has a huge and mature ecosystem of tools and libraries across many platforms and languages. Markdown documents written for one system are almost guaranteed to work for another system, often requiring only minimal or even no changes at all.

The same cannot be said of MDX, which only works if your app is written in JavaScript and renders its UI using React. Having said that, official support for Vue seems to be in the works, and Svelte developers can use the independently developed MDSveX, which is .

The ugly

While MDX is largely a superset of Markdown, there are some subtle differences that can be very annoying, especially if your Markdown documents include lots of HTML tags or make use of hard line wraps.

Some of these will hopefully be resolved in MDX v2, but for now you’ll have to work around them.

Closing tags

Most markdown implementations let you intersperse your Markdown with HTML. That still works in MDX – provided that you close all your tags, because it’ll be converted to JSX.

So this works:

But this will generate a scary-looking error:

Not a big deal, since the fix is simple to apply and the error messages tell you exactly where things are broken.

Unfortunately, the same cannot be said of the next annoying quirk…

Disappearing whitespace

JSX code bears a strong resemblance to HTML, but that doesn’t mean it always behaves like HTML. For instance, JSX gobbles up whitespace at the beginning and ending of lines. This may cause issues if you have HTML code that spans multiple lines:

If this were interpreted as HTML in Markdown, it would be rendered as follows:

But with JSX all whitespace between the text and the hyperlink is discarded:

Content formatted using Markdown notation doesn’t suffer from this problem. Therefore it’s wise to avoid writing HTML in your Markdown documents unless you absolutely need it. As an added bonus it is also more succinct and easier to read:

Otherwise you can also explicitly add whitespace to your JSX code using either {' '} or <> </>, e.g.

If you find that you need to do this often, you might try to create your own components that handle whitespace for you.

Ending paragraphs

MDX lets you can write your Markdown and JSX in the same file. Your custom JSX components will often be block-level elements, but MDX also supports inline JSX elements. The current version of MDX does an… alright job of telling the two apart, but sometimes it just completely misses the mark.

Let’s say that we have a CustomSpan component that wraps its children into a span, but otherwise does completely nothing:

This does pretty much what you’d expect:

But here’s that same inline element, at the start of a new line due to a hard line wrap:

This time we get a very different result:

Note that MDX prematurely ends the paragraph on the second line here, which in most browsers will cause the spanned element to appear on its own line:

No one will warn you when this happens, which means that you’re on your own here and will have to double-check the generated HTML output manually.

This annoyingly also happens with elements for semantic markup, like <time> and <abbr>, for which no equivalent Markdown notation exists.

I haven’t really found a solution for this yet, other than avoiding the use of HTML elements whenever I can. Sometimes I also have to format my documents in awkward ways to prevent lines from starting with HTML or JSX tags.


All in all, I think MDX as a content format looks promising. A little bit rough around the edges, but good enough for production use nonetheless.

  1. MDX lets you include React components in your Markdown documents, which makes it easier to create interactive documents

  2. MDX is a bit harder to work with from a developer’s perspective

  3. MDX has quirks that make it cumbersome to use in specific cases