mdx Documentation

Markdown for the component era

19,733 stars JavaScript JavaScript 1 file Β· ~14,546 tokens #jsx#markdown#mdx#react#remark#unified#vue
RAW Doc

File: README.md

MDX

Markdown for the component era

Build
Coverage
Sponsors
Backers
Chat

MDX is an authorable format that lets you seamlessly write JSX in
your markdown documents.
You can import components, such as interactive charts or alerts, and embed them
within your content.
This makes writing long-form content with components a blast.
πŸš€

mdx
import {Chart} from './snowfall.js'
export const year = 2013

# Last year’s snowfall

In {year}, the snowfall was above average.
It was followed by a warm spring which caused
flood conditions in many of the nearby rivers.

<Chart year={year} color="#fcb32c" />

See Β§ What is MDX for more info on the
format.
See Β§ Playground to try it out.

What is this?

This GitHub repository contains several packages for compiling the MDX format to
JavaScript, integrating with bundlers such as webpack and Rollup, and for using
it with frameworks such as React, Preact, and Vue.

See Β§ Getting started for how to
integrate MDX into your project.

Security

See Β§ Security on our site for information.

Contribute

See Β§ Contribute on our site for ways to get started.
See Β§ Support for ways to get help.

This project has a code of conduct.
By interacting with this repository, organization, or community you agree to
abide by its terms.

See Β§ Sponsor on our site for how to help financially.

| Vercel
| Motif
| HashiCorp
| GitBook
| Gatsby

| | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Netlify

| Coinbase
| ThemeIsle
| Expo
| Boost Note
| Markdown Space
| Holloway
| | |
| You? | | | | | | | | |

License

MIT Β© Compositor and Vercel


File: Readme.md

MDX

Markdown for the component era

Build
Coverage
Sponsors
Backers
Chat

MDX is an authorable format that lets you seamlessly write JSX in
your markdown documents.
You can import components, such as interactive charts or alerts, and embed them
within your content.
This makes writing long-form content with components a blast.
πŸš€

mdx
import {Chart} from './snowfall.js'
export const year = 2013

# Last year’s snowfall

In {year}, the snowfall was above average.
It was followed by a warm spring which caused
flood conditions in many of the nearby rivers.

<Chart year={year} color="#fcb32c" />

See Β§ What is MDX for more info on the
format.
See Β§ Playground to try it out.

What is this?

This GitHub repository contains several packages for compiling the MDX format to
JavaScript, integrating with bundlers such as webpack and Rollup, and for using
it with frameworks such as React, Preact, and Vue.

See Β§ Getting started for how to
integrate MDX into your project.

Security

See Β§ Security on our site for information.

Contribute

See Β§ Contribute on our site for ways to get started.
See Β§ Support for ways to get help.

This project has a code of conduct.
By interacting with this repository, organization, or community you agree to
abide by its terms.

See Β§ Sponsor on our site for how to help financially.

| Vercel
| Motif
| HashiCorp
| GitBook
| Gatsby

| | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Netlify

| Coinbase
| ThemeIsle
| Expo
| Boost Note
| Markdown Space
| Holloway
| | |
| You? | | | | | | | | |

License

MIT Β© Compositor and Vercel


File: readme.md

MDX

Markdown for the component era

Build
Coverage
Sponsors
Backers
Chat

MDX is an authorable format that lets you seamlessly write JSX in
your markdown documents.
You can import components, such as interactive charts or alerts, and embed them
within your content.
This makes writing long-form content with components a blast.
πŸš€

mdx
import {Chart} from './snowfall.js'
export const year = 2013

# Last year’s snowfall

In {year}, the snowfall was above average.
It was followed by a warm spring which caused
flood conditions in many of the nearby rivers.

<Chart year={year} color="#fcb32c" />

See Β§ What is MDX for more info on the
format.
See Β§ Playground to try it out.

What is this?

This GitHub repository contains several packages for compiling the MDX format to
JavaScript, integrating with bundlers such as webpack and Rollup, and for using
it with frameworks such as React, Preact, and Vue.

See Β§ Getting started for how to
integrate MDX into your project.

Security

See Β§ Security on our site for information.

Contribute

See Β§ Contribute on our site for ways to get started.
See Β§ Support for ways to get help.

This project has a code of conduct.
By interacting with this repository, organization, or community you agree to
abide by its terms.

See Β§ Sponsor on our site for how to help financially.

| Vercel
| Motif
| HashiCorp
| GitBook
| Gatsby

| | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Netlify

| Coinbase
| ThemeIsle
| Expo
| Boost Note
| Markdown Space
| Holloway
| | |
| You? | | | | | | | | |

License

MIT Β© Compositor and Vercel


File: docs/blog/conf.mdx

import {Note} from '../_component/note.jsx'

export const info = {
author: [
{github: 'johno', name: 'John Otander'}
],
modified: new Date('2025-01-27'),
published: new Date('2020-07-31')
}

**Note**: This is an old blog post. The below is kept as is for historical purposes.

MDXConf

MDXConf is a free and online conference for the MDX community.
Whether you’re just learning about MDX or an expert, there’ll be something for
you! {/* more */}

August 24th, 2020 at 8am PDT/3pm UST Online β€’ Free

Watch

The conference is now over, but you can still watch the recordings!

Watch the talks β†’

About

Join us for the first MDX conference!
We’ll stream it directly to you, for free.

MDX has grown rapidly since the first commit two and a half years ago.
We’d like to celebrate our accomplishments so far, and talk about what lies
ahead.
We’ve got lots of plans.

Learn how MDX increases developer productivity, improves educational
content authoring, and even peek behind the curtains to see how MDX works.

Speakers

Chris Biscardi

]

Keynote: The past, present, and future of MDX

Monica Powell

Migrating to MDX

Laurie Barth

MDX v2 syntax

Cole Bemis

Demystifying MDX

Prince Wilson

Personal site playgrounds

Kathleen McMahon

Digital gardening with MDX magic

Rodrigo Pombo

The X in MDX

Jonathan Bakebwa

MDX and Vue/Nuxt

Sign up

**Note**: Sign up is closed.

FAQ

What if I can’t make it on August 24th?

We’ll miss you, but you won’t miss out!
All talks will be recorded and released the day of the conference.
You can catch up with the talks, or rewatch them, whenever convenient.

Will the talks be transcribed?

Yes.

Is there a code of conduct?

Absolutely.
We’re dedicated to providing a harassment-free experience for everyone.
We will not tolerate harassment of participants in any form.
We’ve adopted the Party Corgi Network’s Code of Conduct.
We will have moderators to ensure that the code of conduct is followed.

Do you have a different question?

Reach out to us.


File: docs/blog/custom-pragma.mdx

import {Note} from '../_component/note.jsx'

export const info = {
author: [
{github: 'christopherbiscardi', name: 'Chris Biscardi'}
],
modified: new Date('2021-11-01'),
published: new Date('2019-03-11')
}

**Note**: This is an old blog post. The steps described in it are no longer performed by MDX. It now uses an JavaScript AST first rather than generating a string of JSX. It is also no longer required for extra glue code, that combines MDX with a specific framework, to be used on the client. See [Β§ How MDX works](/docs/using-mdx/#how-mdx-works) and [ΒΆ Architecture](/packages/mdx/#architecture) for more info. The below is kept as is for historical purposes.

Custom pragma

MDXTag, for those that aren’t aware, is a critical piece in the way
MDX replaces HTML primitives like and `<h1>` with custom React Components. [I’ve previously written](https://www.christopherbiscardi.com/post/codeblocks-mdx-and-mdx-utils) about the way `MDXTag` works when trying to replace the tag
with a custom code component.
mdx-utils
contains the methodology for pulling the props around appropriately
through the MDXTag elements that are inbetween pre and code.

{/* more */}

tsx
exports.preToCodeBlock = preProps => {
  if (
    // children is MDXTag
    preProps.children &&
    // MDXTag props
    preProps.children.props &&
    // if MDXTag is going to render a <code>
    preProps.children.props.name === 'code'
  ) {
    // we have a <code> situation
    const {
      children: codeString,
      props: {className, ...props}
    } = preProps.children.props

    return {
      codeString: codeString.trim(),
      language: className && className.split('-')[1],
      ...props
    }
  }
  return undefined
}

So MDXTag is a real Component in the middle of all of the other MDX
rendered elements.
All of the code is included here for reference.

tsx
import React, {Component} from 'react'

import {withMDXComponents} from './mdx-provider'

const defaults = {
  inlineCode: 'code',
  wrapper: 'div'
}

class MDXTag extends Component {
  render() {
    const {
      name,
      parentName,
      props: childProps = {},
      children,
      components = {},
      Layout,
      layoutProps
    } = this.props

    const Component =
      components[`${parentName}.${name}`] ||
      components[name] ||
      defaults[name] ||
      name

    if (Layout) {
      return (
        <Layout components={components} {...layoutProps}>
          <Component {...childProps}>{children}</Component>
        </Layout>
      )
    }

    return <Component {...childProps}>{children}</Component>
  }
}

export default withMDXComponents(MDXTag)

MDXTag is used in the hast to estree conversion,
which is the final step in the MDX AST pipeline.
Every renderable element is wrapped in an MDXTag, and MDXTag handles
rendering the element later.

tsx
return `<MDXTag name="${node.tagName}" components={components}${
  parentNode.tagName ? ` parentName="${parentNode.tagName}"` : ''
}${props ? ` props={${props}}` : ''}>${children}</MDXTag>`

A concrete example

The following MDX

mdx
# a title

    and such

testing

turns into the following React code

tsx
export default ({components, ...props}) => (
  <MDXTag name="wrapper" components={components}>
    <MDXTag name="h1" components={components}>{`a title`}</MDXTag>{' '}
    <MDXTag name="pre" components={components}>
      <MDXTag
        name="code"
        components={components}
        parentName="pre"
        props={{metaString: null}}
      >{`and such `}</MDXTag>
    </MDXTag>{' '}
    <MDXTag name="p" components={components}>{`testing`}</MDXTag>
  </MDXTag>
)

resulting in the following HTML

html
<h1>a title</h1>
  
    `and such`
  
  testing

createElement

With the new approach, the above MDX transforms into this new React code

tsx
const layoutProps = {}
export default function MDXContent({components, ...props}) {
  return (
    <MDXLayout
      {...layoutProps}
      {...props}
      components={components}
      mdxType="MDXLayout"
    >
      <h1>{`a title`}</h1>
      
        <code parentName="pre" {...{}}>{`and such
`}</code>
      
      {`testing`}
    </MDXLayout>
  )
}

MDXContent.isMDXComponent = true

Notice how now the React elements are plainly readable without
wrapping MDXTag.

Now that we’ve cleaned up the intermediary representation, we need to
make sure that we have the same functionality as the old MDXTag.
This is done through a custom createElement implementation.
Typically when using React, we use React.createElement to render the elements
on screen.
This is even true if you’re using JSX because JSX tags such as `` compile
to createElement calls.
So this time instead of using React.createElement we’ll be using our own.

Reproduced here is our createElement function and the logic for how
we decide whether or not MDX should take over the rendering of the
createElement call.

tsx
export default function (type, props) {
  const args = arguments
  const mdxType = props && props.mdxType

  if (typeof type === 'string' || mdxType) {
    const argsLength = args.length

    const createElementArgArray = new Array(argsLength)
    createElementArgArray[0] = MDXCreateElement

    const newProps = {}
    for (let key in props) {
      if (hasOwnProperty.call(props, key)) {
        newProps[key] = props[key]
      }
    }
    newProps.originalType = type
    newProps[TYPE_PROP_NAME] = typeof type === 'string' ? type : mdxType

    createElementArgArray[1] = newProps

    for (let i = 2; i < argsLength; i++) {
      createElementArgArray[i] = args[i]
    }

    return React.createElement.apply(null, createElementArgArray)
  }

  return React.createElement.apply(null, args)
}

Vue

One really cool application of the new output format using a custom
createElement is that we can now write versions of it for Vue and other
frameworks.
Since the pragma insertion is the responsibility of the webpack (or other
bundlers) loader, swapping the pragma can be an option in mdx-loader as long as
we have a Vue createElement to point to.


File: docs/blog/index.mdx

{
/**

  • @import {Item} from '../_component/sort.js'
    */

/**

  • @typedef Props
  • @property {Item} navigationTree
    */
    }

import assert from 'node:assert/strict'
import {BlogGroup} from '../_component/blog.jsx'

export const info = {
author: [{name: 'MDX Contributors'}],
modified: new Date('2024-07-04'),
published: new Date('2021-11-01')
}
export const navExcludeGroup = true
export const navigationSortItems = 'navSortSelf,meta.published:desc'
export const navSortSelf = 7

Blog

The latest news about MDX.

{
(function () {
const navigationTree = props.navigationTree
const category = navigationTree.children.find(function (item) {
return item.name === '/blog/'
})
assert(category)

text
return (
  <nav>
    
  </nav>
)

})()
}


File: docs/blog/shortcodes.mdx

import {Note} from '../_component/note.jsx'

export const info = {
author: [
{github: 'johno', name: 'John Otander'}
],
modified: new Date('2021-11-01'),
published: new Date('2019-05-14')
}

**Note**: This is an old blog post. The features described in it are currently documented at [Β§ MDX provider](/docs/using-mdx/#mdx-provider). The below is kept as is for historical purposes.

Shortcodes

An exciting new feature in MDX v1 is global shortcodes.
This allows you to expose components to all of your documents in your app or
website.
This is a useful feature for common components like YouTube embeds, Twitter
cards, or anything else frequently used in your documents.

{/* more */}

If you have an application wrapper for your MDX documents
you can add in components with the MDXProvider:

tsx path="src/app.js"
import React from 'react'
import {MDXProvider} from '@mdx-js/react'
import {TomatoBox, Twitter, YouTube} from './ui'

const shortcodes = {TomatoBox, Twitter, YouTube}

export default ({children}) => (
  <MDXProvider components={shortcodes}>{children}</MDXProvider>
)

Then, any MDX document that’s wrapped in App has access to YouTube,
Twitter, and TomatoBox.
Shortcodes are nothing more than components, so you can reference them anywhere
in an MDX document with JSX.

mdx path="example.mdx"
# Hello world!

Here’s a YouTube shortcode:

<YouTube tweetId="1234" />

Here’s a YouTube shortcode wrapped in TomatoBox:

<TomatoBox>
  <YouTube videoId="1234" />
</TomatoBox>

That’s it.
πŸŽ‰ πŸš€

Huge thanks to Chris Biscardi
for building out most of this functionality.


File: docs/blog/v1.mdx

import {Note} from '../_component/note.jsx'

export const info = {
author: [
{github: 'johno', name: 'John Otander'}
],
modified: new Date('2025-01-27'),
published: new Date('2019-04-11')
}

**Note**: This is an old blog post. [ZEIT is now Vercel](https://rauchg.com/2020/vercel). An β€œ`@mdx` pragma” is no longer needed. The below is kept as is for historical purposes.

MDX goes stable

It’s been a year and a half since the first MDX commit and a year since MDX was
first announced at ZEIT Day.
MDX is a radical paradigm shift in how to write immersive content using
components.
It’s an open, authorable format that
makes it fun to write again.

{/* more */}

Since announcing MDX we’ve been working on numerous bug fixes, new features,
better parsing, and integration tests.
Now, we think it’s ready.
We’re happy to finally release v1!

πŸŽ‰ What’s new?

Here’s a rough breakdown on what we’ve been working on:

Parsing

MDX document parsing is significantly improved.
We won’t get into the nitty gritty here, but we’ve seen how MDX is used in
real-world projects, integrated the edge cases we came across into our test
suite, and now handle JSX, imports, and exports much more intuitively.
Please open an issue if you find a case we haven’t covered!😸

remark-mdx

remark-mdx is the syntactic extension for MDX in remark.
It provides the parsing functionality for MDX as a
remark plugin.
That sounds a bit meta.
What it means is that before we had the syntax parsing bits in the library
(unusable from the outside), and now it’s externalized (usable from the
outside).
This is useful if you want to inspect or transform MDX documents.
For example, it allows tools like prettier to use the exact same parser used by
MDX core.
Or you could use remark-mdx in combination with
remark-lint to check your MDX.

Custom pragma

With v1 we’ve moved away from using MDXTag and are using a custom pragma which
wraps React.createElement.
We decided to update this approach so the JSX output is more legible,
lighterweight, and more customizable.
This means MDX can be used with any React, Vue, Preact, or any other library
with JSX support
.

Special thanks to @christopherbiscardi
for implementing this feature.

Read the blog post

πŸ“š Documentation

Good libraries need great docs, so we’ve been working on adding content and
improving the overall documentation website experience.

Special thanks to @jxnblk and
@wooorm for their help improving the docs and
updating the build tooling.

Breaking changes

In order to make some improvements we were forced to introduce a few breaking
changes.
These were the result of real-world production testing and feedback.
The community has evolved and we’ve come up with newer, better ideas over the
last year.
We have made sure the impact is small and have written a full migration guide.

  • 🚨@mdx-js/tag is replaced by @mdx-js/react and an @mdx pragma
    β€” migration guide
  • MDXProvider now merges component contexts when nested
    β€” migration guide
  • React support now requires >= 16.8 in @mdx-js/react
    β€” migration guide

Read the full v1 migration guide

Deprecations

We only needed to introduce one deprecation.
The mdPlugins and hastPlugins options have been renamed remarkPlugins and
rehypePlugins respectively.
For the time being we will issue a warning when the old options are used.
In v2, the old options will be removed.

πŸ“ˆ Growth

A major release is always a good time to take a step back and reflect on what’s
been happening in terms of growth and the greater community.
The ecosystem surrounding MDX has already grown larger than we ever dreamed.
We’ve also seen projects/products/application we never even imagined.

Numbers

  • Downloads: 125,000/week, 2.4M total
  • Stars: 6,200
  • Contributors: 50
  • Pull requests: 281
  • Commits: 670

The contributor growth is one of the most important aspects here as we have
numerous community members that are familiar with MDX internals.
This allows us to continually improve the project and spread the workload
against an ever growing team of contributors.

See the contributor graph

Ecosystem

πŸ›£ Roadmap

With v1 released we have a roadmap in place that we’ll continue working towards
over the next 6 months or so in addition to bug fixes and parsing issues we
might encounter.

Vue support

Supporting Vue is an important goal for MDX and is one of the primary reasons
we’ve rearchitected MDX to use custom pragma.
We’re delighted that we now have an alpha version for Vue working.
We’d love it if anyone from the Vue community wants to give it a try and provide
feedback.

See the Vue example

Blocks project

One of the key missing aspects of authoring MDX documents is the editing
experience.
Currently, there isn’t an approachable way to write MDX unless you enjoy working
in a text editor and writing raw Markdown/code.
We’d like to solve that and have begun work on an MDX β€œblocks editor” that’s a
content-focused WYSIWYG.
Not to mention, we’ll be doing all that we can to make sure the editor is as
accessible as it can be from the beginning.

When we have a beta ready we will be open sourcing it and announcing, so stay
tuned.

Check out the Blocks project

unified collective

MDX is part of the unified collective, which is an open source ecosystem for
dealing with many sources of content.
unified projects are used all over the web, and it would never be possible
without financial support from our fine sponsors.

πŸ™ Thanks

We’d like to say thanks to all our contributors and our happy users.
Special thanks to
@wooorm,
@silvenon,
@timneutkens,
@ChristopherBiscardi,
@jxnblk,
@alexandernanberg,
@jescalan,
@Jarred-Sumner,
@leimonio,
@ticky,
@jamesknelson,
@pshrmn,
@rauchg,
@joelhooks,
@jlengstorf,
@johnlindquist,
@kyleamathews,
@kentcdodds,
@wesbos,
@rosew,
@pedronauck,
@tayiorbeii,
@nickbender,
@ntaylor89,
@mxstbr,
@manovotny,
@xyc,
@filoxo,
@millette,
@hugmanrique,
@johnsherrard,
@sw-yx,
and anyone we may have forgotten.


File: docs/blog/v2.mdx

import {Note} from '../_component/note.jsx'
export const info = {
author: [
{github: 'wooorm', name: 'Titus Wormer'}
],
modified: new Date('2025-01-27'),
published: new Date('2022-02-01')
}

**Note**: This is an old blog post. The below is kept as is for historical purposes. **Note**: Info on how to migrate is available in our [Version 2 migration guide][migrating].

MDX 2

Version 2 of MDX was released after years of hard work, and has many
improvements.
Here are the highlights:

{/* more */}

  • πŸ“ Improved syntax makes it easier to use markdown in JSX
  • πŸ§‘β€πŸ’» JavaScript expressions turn {2 * Math.PI} into {2 * Math.PI}
  • πŸ”Œ New esbuild, Rollup, and Node.js integrations
  • βš›οΈ Any JSX runtime: React, Preact, Vue, Emotion, you name it, they’re
    all supported
  • 🌳 Improved AST exposes more info in greater detail
  • πŸƒβ€β™€οΈ Compiles at least 25% faster
  • 🚴 Generated code runs twice as fast (100% faster)
  • πŸš„ Bundle size of @mdx-js/mdx is more than three times as small
    (250% smaller)
  • 🧡 …and much, so much more

It’s been 4 years since this project was announced.
2Β½ since we released our stable version 1.
We’re proud to finally release v2!
Let’s dive in!

Contents

Improvements to the MDX format

We’ve spent a lot of time thinking and trying out different ways to improve the
format.
Originally, the format was very close to how markdown, and HTML in markdown,
works.
We found that the old behavior often yielded unexpected results.
In version 2, we shift the format a little bit closer to how JS(X) works.

Take for example this MDX file:

mdx chrome=no
*hi*?


  # hi?


<main>
  

    # hi?

  
</main>
text
In version 1, that was equivalent to the following JSX:

```tsx chrome=no
<>
  *hi*?
  
    # hi?
  
  <main>
    
      `# hi?`
    
  </main>
</>
```



In version 2, it’s equivalent to the following JSX:

```tsx chrome=no
<>
  *hi*?
  
    <h1>hi?</h1>
  
  <main>
    
      <h1>hi?</h1>
    
  </main>
</>
```

We believe it’s more intuitive that markdown β€œinlines” such as emphasis can form
between tags on the same line (first ), β€œblocks” such as headings can form if they’re on their own line (second ), and indentation is allowed
rather than forming code (third ``).

We also added support for JavaScript expressions, take for example:

text
```mdx path="expressions.mdx"
export const authors = [
  {name: 'Jane', email: '[email protected]'},
  {name: 'John', github: '@johno'}
]
export const published = new Date('2022-02-01')

Written by: {new Intl.ListFormat('en').format(authors.map(d => d.name))}.

Published on: {new Intl.DateTimeFormat('en', {dateStyle: 'long'}).format(published)}.
```



```tsx path="equivalent.jsx"
<>
  Written by: Jane and John.
  Published on: February 1, 2022.
</>
```

As the format moves a little further from markdown towards JSX, we’ve added
support for loading β€œnormal” markdown without our syntax extensions.
If you’re using our bundler integration @mdx-js/loader (or @mdx-js/rollup,
@mdx-js/esbuild, or @mdx-js/node-loader, see next section), then that’ll
just work: import readme.mdx and it’s seen as the MDX format, import
readme.md and it’s seen as markdown, based on their extensions.

The MDX format is described in Β§ What is MDX?

Rollup, esbuild, and other integrations

When we started out, Babel, webpack, and React were ubiquitous in the JavaScript
ecosystem and we built MDX on them.
For version 2, we worked hard to make them optional.
They’re no longer required and MDX can more easily be used with other tools.

On the bundler side, we’ve added new integrations: @mdx-js/esbuild for
esbuild (an extremely fast bundler) and @mdx-js/rollup for Rollup (a bundler
that’s also used in Vite and WMR).
You can even import MDX files directly in Node.js with our new
@mdx-js/node-loader.

On the runtime side, we can now compile JSX away to normal JavaScript and
no longer need framework-specific code to glue them together with MDX.
Now any JSX runtime, whether classic or automatic, is supported.
This means MDX can be used with React, Preact, Vue, Emotion, Theme UI, Ink, you
name it, plus anything that’s yet to be invented!

See Β§ Getting started for a quick start but also in-depth
info on how to integrate MDX with many different tools.

Architectural improvements

To make the syntax of the MDX format better and to allow new integrations and
arbitrary JSX runtimes, we’ve rewritten almost everything.
Part of that effort was micromark, which is another story, but it means
we’re fully CommonMark (and optionally GFM) compliant, while also understanding
more about MDX files.

Now we can throw an early error when there’s a typo and point to exactly where
it happened, instead of a later bundler like webpack complaining about an error
in an intermediate, unrecognizable, and broken string of JavaScript.
It also means that we have a new AST which describes the MDX syntax in more
detail β€” we even expose the embedded JavaScript.
This detailed AST allows plugins to enhance MDX in powerful new ways.
It also helped solve edge cases where MDX would previously crash.
And it let us drop Babel.

This new architecture results in 25% faster compilation, generated code
that runs twice as fast (100% faster), and that the bundle size of
@mdx-js/mdx is more than three times as small (250% smaller).

See ΒΆ Architecture in @mdx-js/mdx for more on how our compiler
works.
See Β§ Extending MDX for several plugins that use the new tree to
enhance MDX, how to use them and other plugins, and how to create plugins.

TypeScript

All @mdx-js/* packages are now fully typed with TypeScript
through JSDoc comments.
That means our APIs are exposed as TypeScript types but also that our projects
are type safe internally.

We’ve published @types/mdx, a types-only package that can be used
with any (community) integration.
You can use it, if you’re importing MDX files, to type those imported
components.

See ΒΆ TypeScript in Β§ Getting started for more on how to use configure
TypeScript.

Docs & site

MDX is used and liked a lot.
Before version 1 we had amassed a total of 2.5m downloads.
Now we hit that number every week.
Our core compiler @mdx-js/mdx is used in 61k projects.
Our GitHub repo has 11.6k stars.

Many people help, often with docs.
85 contributors committed to our repo since version 1.
We’re grateful for these contributions and all those individual insights,
but over the years it did result in some inconsistencies and duplicated content.

For version 2, we rewrote our docs from beginning to end to tell a consistent
story for new users, folks that do complex AST and compiler stuff, and
anyone in between.

We also made a new website.
It’s built on MDX of course, unified itself, and React Server Components
(RSC)
.
While we dogfood the former two as they’re projects we maintain, and the
latter is extremely experimental, we think compiling things ahead of time and
betting on hybrid models, compared to completely server-side sites or completely
client-side apps, is the smart choice for us and the web’s future.

Our new site is heavily optimized and fast, gorgeous (subjective but hey), has
rich metadata, and scores very well in performance and accessibility review
tools such as Lighthouse and axe.

See Β§ Contribute for more on how to help.

Breaking changes

When you’re ready to migrate, please see the
Version 2 migration guide.

Thanks

We’d like to say thanks to all our contributors and our happy users.
Special thanks to
John Otander (@johno),
Christian Murphy (@ChristianMurphy),
JounQin (@JounQin),
Jack Bates (@jablko),
Sam Chen (@chenxsan),
Sam Robbins (@samrobbins85),
Remco Haszing (@remcohaszing),
LB (@laurieontech),
Gabriel Kirkley (@gdgkirkley>),
Hung-I Wang (@Gowee),
Ilham Wahabi (@iwgx),
Kaito Sugimoto (@HelloRusk),
Karl Horky (@karlhorky),
Katie Hughes (@glitteringkatie),
Lachlan Campbell (@lachlanjc),
Marcy Sutton (@marcysutton),
Marius Gundersen (@mariusGundersen),
Marius-Remus Mate,
Mark Skelton (@mskelton),
Martin V (@ndresx),
Matija Marohnić (@silvenon),
Michael Oliver (@michaeloliverx),
MichaΓ«l De Boey (@MichaelDeBoey),
Muescha (@muescha),
Norviah (@Norviah),
Paul Scanlon (@PaulieScanlon),
Peter Mouland (@peter-mouland),
Prince Wilson (@maxcell),
Rafael Almeida (@rafaelalmeidatk),
Rodrez (@rodrez),
Rongjian Zhang (@pd4d10),
Taeheon Kim (@lonyele),
Tom Parker-Shemilt (@palfrey),
Try Ajitiono (@imballinst),
Yamagishi Kazutoshi (@ykzts),
Yoav Kadosh (@ykadosh),
Yordis Prieto (@Yordis),
Adrian Foong (@adrfoong),
Dan Abramov (@gaearon),
@ihupoo,
@nikhog,
@redallen,
Akshay Kadam (@deadcoder0904),
я ΠΊΠΎΡ‚ΠΈΠΊ ΠΏΡƒΡ€-ΠΏΡƒΡ€ (@mvasilkov),
Anders D. Johnson (@AndersDJohnson),
Andrew Aylett (@andrewaylett),
Ankeet Maini (@ankeetmaini),
Biswas Nandamuri (@Biswas-N),
Bret (@bcomnes),
Chris Chinchilla (@ChrisChinchilla),
Christopher Biscardi (@ChristopherBiscardi),
Dan Overton (@dan-overton),
Domitrius (@domitriusclark),
Dovi Winberger (@dowi),
Emmie PΓ€ivΓ€rinta (@emmiep),
Eugene Ghanizadeh (@loreanvictor),
and anyone we may have forgotten.


File: docs/blog/v3.mdx

import {Note} from '../_component/note.jsx'
export const info = {
author: [
{github: 'wooorm', name: 'Titus Wormer'}
],
modified: new Date('2025-01-27'),
published: new Date('2023-10-24')
}

**Note**: Info on how to migrate is available in our [Version 3 migration guide][migrating].

MDX 3

Version 3 already!
This major version contains a couple small changes.
For most folks, updating Node.js and plugins is all that’s needed!

{/* more */}

Contents

Breaking changes

The main breaking change is that Node.js 16 is now the minimum supported
version.

Across the ecosystem there were several small internal breaking changes.
Everything’s released already.
You can update all plugins now.
If you ran into problems before, it should work now.

We also removed some infrequently used deprecated APIs.
You’re likely fine but gloss over the v3 migration guide if you
get errors.

Important to note when you use your lesser-known but powerful evaluate, run,
or outputFormat: 'function-body' APIs, please pass the baseUrl option.
That makes sure import.meta.url, import, and export work.
You’ll get a runtime error when those features are used otherwise.

Improvements to the MDX format

There’s also a few small improvements to the MDX format, some of which
technically breaking.

Adjacent block JSX and expressions in MDX

We now accept block expressions right next to block JSX tags:

mdx chrome=no
<style>{`

  h1 {
    color: blue;
  }

`}</style>

Previously, there was a syntax error, and you had to add a newline between the
angle brackets and the braces.

Await in MDX

We now accept await syntax:

mdx
{await Promise.resolve(42)}

Most frameworks don’t support promises.
Whether this works depends on that.

Previously, there was a runtime error that await was used in a context where
it wasn’t allowed.

ES2024 in MDX

You can now use modern JavaScript syntax in MDX.
Acorn, used internally, is now instructed to use ES2024.

Miscellaneous

I refactored all the docs.
Updating every use example where needed.
I also wrote a guide on how to inject components from anywhere:
Β§ Injecting components.

The site is a lot faster.
There’s a nice improved playground too: try it out! Β».
We also have proper syntax highlighting here, thanks to
wooorm/markdown-tm-language
and wooorm/starry-night.

The generated JS code is a little cleaner (the JSX pragma comment is removed
and objects are sorted where needed), it also uses spreads instead of
Object.assign, there’s a 'use strict' added when needed, and the
MDXContent is exported immediately.

Thanks

We’d like to say thanks to all our contributors and our happy users.
Special thanks to
εŒ—ι›δΊ‘δΎ (@BeiyanYunyi),
Christian Murphy (@ChristianMurphy),
JokcyLou (@Jokcy),
MaΓ«l Nison (@arcanis),
Andreas Deininger (@deining),
Remco Haszing (@remcohaszing),
SΓ©bastien Lorber (@slorber),
VΓ­ctor FernΓ‘ndez (@victor23k),
Titus Wormer (@wooorm),
and anyone we may have forgotten.


File: docs/community/about.mdx

import {Note} from '../_component/note.jsx'

export const info = {
author: [
{github: 'wooorm', name: 'Titus Wormer'}
],
modified: new Date('2025-01-27'),
published: new Date('2021-10-06')
}
export const navSortSelf = 4

About

This article explains in short how MDX came to be and why it exists.
It also gives thanks to the people who’ve helped make it and inspired it.

{/* more */}

What is MDX?

MDX is the combination of markdown with JSX.
See Β§ What is MDX? for more info.

Why MDX?

Markdown does not have a syntax for custom components.
MDX solves this.

There are many languages objectively better than markdown, however, markdown is
great because:

  • It looks like what it means and is relatively easy to read
  • Although images are confusing, most stuff is relatively simple to write
  • It’s loose and ambiguous: it may not work but you won’t get an error (great
    for someone posting a comment to a forum if they forgot an asterisk)

Markdown does have a way to extend it, HTML, but that has drawbacks:

  • HTML in markdown is naΓ―ve, how it’s parsed sometimes doesn’t make sense
  • HTML is unsafe by default, so it’s sometimes (partially) unsupported
  • HTML and markdown don’t mix well, resulting in confusing rules such as
    blank lines or markdown="1" attributes
  • HTML is coupled with browsers, markdown is useful for other things too

The frontend world has an alternative to HTML: JSX.
JSX is great, amongst other things, because:

  • It has a relatively familiar syntax (like XML)
  • It’s agnostic to semantics and intended for compilers (can have any
    domain-specific meaning)
  • It’s strict and unambiguous (great if an author forgot a slash somewhere, as
    they’ll get an error early, instead of a book going to print with broken
    stuff in it)

Who governs MDX?

The project is governed by the
unified collective.

Who created MDX?

The idea of combining markdown, JavaScript, and JSX was a
collaborative effort by
Guillermo Rauch (@rauchg),
James K. Nelson (@jamesknelson),
John Otander (@johno),
Tim Neutkens (@timneutkens),
Brent Jackson (@jxnblk),
Jessica Stokes (@ticky), and more.

While everyone above was key to MDX, we want to stress the involvement of
John Otander (@johno).
John wrote most of the code for the first alpha and later stable version 1 of
this project!

Logo designs were created by Evil Rabbit of Vercel.

What projects inspired MDX?

The following projects, languages, and articles helped shape MDX either in
implementation or inspiration.

The markdown and JSX languages inspired MDX.
Markdown was created by John Gruber (@gruber).
CommonMark, the most popular markdown variant, by John McFarlane
(@jgm) et al.
JSX was created by Sebastian MarkbΓ₯ge (@sebmarkbage) et
al. at Facebook, Inc.

The @mdx-js/* projects currently make heavy use of unified (specifically
micromark, remark and rehype) and Acorn.
unified, remark, rehype, and related tools were created by Titus Wormer
(@wooorm) et al.
Acorn by Marijn Haverbeke (@marijnh) et al.

The following projects inspired @mdx-js/* originally:

{/* Note: please keep the original project names intact: */}

The following articles inspired @mdx-js/* originally:


File: docs/community/contribute.mdx

import {Note} from '../_component/note.jsx'

export const info = {
author: [
{github: 'wooorm', name: 'Titus Wormer'}
],
modified: new Date('2025-01-27'),
published: new Date('2018-11-04')
}
export const navSortSelf = 2

Contribute

This article explains how to contribute to MDX.
Please read through the following guidelines.

{/* more */}

**Important**: before participating in our community, please read our [code of conduct][coc]. By interacting with this repository, organization, or community you agree to abide by its terms.

Contributions

There’s several ways to contribute, not just by writing code.
If you have questions, see Β§ Support.
If you can provide financial support, see Β§ Sponsor.

Improve docs

As a user you’re perfect for helping us improve our docs.
Typo corrections, error fixes, better explanations, new examples, etcetera.
All MDX docs live in docs/.

You can run the docs locally, see ΒΆ Site below.

Improve issues

Some issues lack information, aren’t reproducible, or are just incorrect.
You can help by trying to make them easier to resolve.
Existing issues might benefit from your unique experience or opinions.

Write code

Code contributions are very welcome.
It’s probably a good idea to first post a question or open an issue to report a
bug or suggest a new feature before creating a pull request.

Submitting an issue

  • The issue tracker is for issues.
    Use discussions for support
  • Search the issue tracker (including closed issues) before opening a new
    issue
  • Ensure you’re using the latest version of our packages
  • Use a clear and descriptive title
  • Include as much information as possible: steps to reproduce the issue,
    error message, version, operating system, etcetera
  • The more time you put into an issue, the better we will be able to help you
  • The best issue report is a failing test proving it

Submitting a pull request

  • See ΒΆ Project below for info on how the project is structured,
    how to test, and how to build the site
  • Non-trivial changes are often best discussed in an issue first, to prevent
    you from doing unnecessary work
  • For ambitious tasks, you should try to get your work in front of the
    community for feedback as soon as possible
  • New features should be accompanied by tests and documentation
  • Don’t include unrelated changes
  • Test before submitting code by running npm test
  • Write a convincing description of why we should land your pull request:
    it’s your job to convince us

Project

Structure

MDX is a monorepo.
All packages are in packages/.
Documentation is in docs/.

Tests

To run the tests, first do npm install, then do npm test.
This ensures everything is okay, from code style to unit tests to types.

Site

To build the site, first do npm install, then do npm run docs.
This produces the website in public/.

Release

To release a new version, do:

  1. update versions of packages with a patch, minor, or major (make sure to
    update dependency ranges on monorepo packages when needed):
    sh
    npm version minor --workspaces --no-git-tag-version
  2. commit and tag using the version (without v) as the message:
    sh
    git commit --all --message 1.2.3 && git tag 1.2.3 && git push && git push --tags
  3. release to the npm registry:
    sh
    npm publish --workspaces
  4. add a changelog entry for the release on GitHub:
    sh
    open https://github.com/mdx-js/mdx/releases

Resources