import {Note} from '../_component/note.server.js'
export const navSortSelf = 3
export const info = {
  author: [
    {name: 'Titus Wormer', github: 'wooorm', twitter: 'wooorm'}
  ],
  published: new Date('2021-09-30'),
  modified: new Date('2021-11-01')
}

<Note type="important">
  **Note**: V2 is around the corner.
  This website is for that.
  It hasn’t been released yet.
  But you can try out the RC.
  You can be of great help by reading through these docs and letting us know
  what’s confusing or wrong or other suggestions you have.
  See [§ Support][support] for where to ask questions and
  [§ Contribute][contribute] for how to help.
</Note>

# Using MDX

This article explains how to use MDX files in your project.
It shows how you can pass props and how to import, define, or pass components. {/* more */}
See [§ Getting started][start] for how to integrate MDX into your project.
To understand how the MDX format works, we recommend that you start with
[§ What is MDX][what].

## Contents

*   [How MDX works](#how-mdx-works)
*   [MDX content](#mdx-content)
    *   [Props](#props)
    *   [Components](#components)
    *   [Layout](#layout)
*   [MDX provider](#mdx-provider)

## How MDX works

An integration compiles MDX syntax to JavaScript.
Say we have an MDX document, `example.mdx`:

```mdx path="input.mdx"
export const Thing = () => <>World</>

# Hello <Thing />
```

That’s *roughly* turned into the following JavaScript.
The below might help to form a mental model:

```js path="output-outline.jsx"
/* @jsxRuntime automatic @jsxImportSource react */

export const Thing = () => <>World</>

export default function MDXContent() {
  return <h1>Hello <Thing /></h1>
}
```

Some observations:

*   The output is serialized JavaScript that still needs to be evaluated
*   A comment is injected to configure how JSX is handled
*   It’s a complete file with import/exports
*   A component (`MDXContent`) is exported

The *actual* output is:

```js path="output-actual.js"
/* @jsxRuntime automatic @jsxImportSource react */
import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'

export const Thing = () => _jsx(_Fragment, {children: 'World'})

function MDXContent(props = {}) {
  const {wrapper: MDXLayout} = props.components || ({})
  return MDXLayout
    ? _jsx(MDXLayout, Object.assign({}, props, {children: _jsx(_createMdxContent, {})}))
    : _createMdxContent()
  function _createMdxContent() {
     const _components = Object.assign({h1: 'h1'}, props.components)
     return _jsxs(_components.h1, {children: ['Hello, ', _jsx(Thing, {})]})
   }
}

export default MDXContent
```

Some more observations:

*   JSX is compiled away to function calls and an import of React†
*   The content component can be given `{components: {wrapper: MyLayout}}` to
    wrap all content
*   The content component can be given `{components: {h1: MyComponent}}` to use
    something else for the heading

† MDX is not coupled to React.
You can also use it with [Preact][],
[Vue][], [Emotion][],
[Theme UI][],
etc.
Both the classic and automatic JSX runtimes are supported.

## MDX content

We just saw that MDX files are compiled to components.
You can use those components like any other component in your framework of
choice.
Take this file:

```mdx path="example.mdx"
# Hi!
```

It could be imported and used in a React app like so:

```js path="example.js"
import React from 'react'
import ReactDom from 'react-dom'
import Example from './example.mdx' // Assumes an integration is used to compile MDX -> JS.

ReactDom.render(<Example />, document.querySelector('#root'))
```

The main content is exported as the default export.
All other values are also exported.
Take this example:

```mdx path="example.mdx"
export const Thing = () => <>World</>

# Hello <Thing />
```

It could be imported in the following ways:

```js path="example.js"
// A namespace import to get everything:
import * as everything from './example.mdx' // Assumes an integration is used to compile MDX -> JS.
console.log(everything) // {Thing: [Function: Thing], default: [Function: MDXContent]}

// Default export shortcut and a named import specifier:
import Content, {Thing} from './example.mdx'
console.log(Content) // [Function: MDXContent]
console.log(Thing) // [Function: Thing]

// Import specifier with another local name:
import {Thing as AnotherName} from './example.mdx'
console.log(AnotherName) // [Function: Thing]
```

### Props

In [§ What is MDX][what], we showed that JavaScript expressions, inside curly
braces, can be used in MDX:

```mdx path="example.mdx"
import {year} from './data.js'
export const name = 'world'

# Hello {name.toUpperCase()}

The current year is {year}
```

Instead of importing or defining data within MDX, data can also be passed
to `MDXContent`.
The passed data is called `props`.
Take for example:

```mdx path="example.mdx"
# Hello {props.name.toUpperCase()}

The current year is {props.year}
```

This file could be used as:

```js path="example.jsx"
import Example from './example.mdx' // Assumes an integration is used to compile MDX -> JS.

// Use a `createElement` call:
React.createElement(Example, {name: 'Venus', year: 2021})

// Use JSX:
<Example name="Mars" year={2022} />
```

### Components

There is one special prop: `components`.
It takes an object mapping component names to components.
Take this example:

```mdx path="example.mdx"
# Hello *<Planet />*
```

It can be imported from JavaScript and passed components like so:

```js path="example.jsx"
import Example from './example.mdx' // Assumes an integration is used to compile MDX -> JS.

<Example components={{Planet: () => <span style={{color: 'tomato'}}>Pluto</span>}} />
```

You don’t have to pass components.
You can also define or import them within MDX:

```jsx path="example.mdx" language="mdx"
import {Box, Heading} from 'rebass'

MDX using imported components!

<Box>
  <Heading>Here’s a heading</Heading>
</Box>
```

Because MDX files *are* components, they can also import each other:

```jsx path="example.mdx" language="mdx"
import License from './license.md' // Assumes an integration is used to compile MDX -> JS.
import Contributing from './docs/contributing.mdx'

# Hello world

<License />

---

<Contributing />
```

Here are some other examples of passing components:

```js path="example.jsx"
<Example
  components={{
    // Map `h1` (`# heading`) to use `h2`s.
    h1: 'h2',
    // Rewrite `em`s (`*like so*`) to `i` with a goldenrod foreground color.
    em: (props) => <i style={{color: 'goldenrod'}} {...props} />,
    // Pass a layout (using the special `'wrapper'` key).
    wrapper: ({components, ...rest}) => <main {...rest} />,
    // Pass a component.
    Planet: () => 'Neptune',
    // This nested component can be used as `<theme.text>hi</theme.text>`
    theme: {text: (props) => <span style={{color: 'grey'}} {...props} />}
  }}
/>
```

The following keys can be passed in `components`:

*   HTML equivalents for the things you write with markdown such as `h1` for
    `# heading` (see [§ Table of components][toc] for examples)
*   `wrapper`, which defines the layout (but a local layout takes precedence)
*   `*` anything else that is a valid JavaScript identifier (`foo`,
    `Quote`, `_`, `$x`, `a1`) for the things you write with JSX (like
    `<So />` or `<like.so />`, note that locally defined components take
    precedence)**‡**

If you ever wondered what the rules are for whether a name in JSX (so `x` in
`<x>`) is a literal tag name (like `h1`) or not (like `Component`), they are as
follows:

*   If there’s a dot, it’s a member expression (`<a.b>` -> `h(a.b)`),
    which means that the `b` component is taken from object `a`
*   Otherwise, if the name is not a valid identifier, it’s a literal (`<a-b>` ->
    `h('a-b')`)
*   Otherwise, if it starts with a lowercase, it’s a literal (`<a>` -> `h('a')`)
*   Otherwise, it’s an identifier (`<A>` -> `h(A)`), which means a component `A`

### Layout

There is one special component: the layout.
If it is defined, it’s used to wrap all content.
A layout can be defined from within MDX using a default export:

```js language="mdx"
export default function Layout({children}) {
  return <main>{children}</main>;
}

All the things.
```

The layout can also be imported and *then* exported with an `export … from`:

```js language="mdx"
export {Layout as default} from './components.js'
```

The layout can also be passed as `components.wrapper` (but a local one takes
precedence).

## MDX provider

Passing components is typically fine.
Take for example this file:

```mdx path="post.mdx"
# Hello world
```

Used like so:

```js path="app.jsx"
import React from 'react'
import ReactDom from 'react-dom'
import Post from './post.mdx' // Assumes an integration is used to compile MDX -> JS.
import {Heading, /* … */ Table} from './components/index.js'

const components = {
  h1: Heading.H1,
  // …
  table: Table
}

ReactDom.render(
  <Post components={components} />,
  document.querySelector('#root')
)
```

But when you’re nesting MDX files (importing them into each other) it can become
cumbersome.
Like so:

```mdx path="post.mdx"
import License from './license.md' // Assumes an integration is used to compile MDX -> JS.
import Contributing from './docs/contributing.mdx'

# Hello world

<License components={props.components} />

---

<Contributing components={props.components} />
```

To solve this, a *[context][]* can be used in React, Preact, and Vue.
Context provides a way to pass data through the component tree without having to
pass props down manually at every level.
Set it up like so:

1.  Install either [`@mdx-js/react`][mdx-react], [`@mdx-js/preact`][mdx-preact],
    or [`@mdx-js/vue`][mdx-vue],
    depending on what framework you’re using
2.  Configure your MDX integration with
    [`options.providerImportSource`][options-provider-import-source]
    set to that package, so either `'@mdx-js/react'`, `'@mdx-js/preact'`, or
    `'@mdx-js/vue'`
3.  Import `MDXProvider` from that package.
    Use it to wrap your top-most MDX content component and pass it your
    `components` instead:

```diff
 import React from 'react'
 import ReactDom from 'react-dom'
 import Post from './post.mdx' // Assumes an integration is used to compile MDX -> JS.
 import {Heading, /* … */ Table} from './components/index.js'
+import {MDXProvider} from '@mdx-js/react'

 const components = {
   h1: Heading.H1,
   // …
   table: Table
 }

 ReactDom.render(
-  <Post components={components} />,
+  <MDXProvider components={components}>
+    <Post />
+  </MDXProvider>,
   document.querySelector('#root')
 )
```

Now you can remove the explicit and verbose component passing:

```diff
 import License from './license.md' // Assumes an integration is used to compile MDX -> JS.
 import Contributing from './docs/contributing.mdx'

 # Hello world

-<License components={props.components} />
+<License />

 ---

-<Contributing components={props.components} />
+<Contributing />
```

When `MDXProvider`s are nested, their components are merged.
Take this example:

```jsx
<>
  <MDXProvider components={{h1: Component1, h2: Component2}}>
    <MDXProvider components={{h2: Component3, h3: Component4}}>
      <Content />
    </MDXProvider>
  </MDXProvider>
</>
```

…which results in `h1`s using `Component1`, `h2`s using `Component3`, and `h3`s
using `Component4`.

To merge differently or not at all, pass a function to `components`.
It’s given the current context `components` and what it returns will be used
instead.
In this example the current context components are discarded:

```jsx
<>
  <MDXProvider components={{h1: Component1, h2: Component2}}>
    <MDXProvider components={() => ({h2: Component3, h3: Component4})}>
      <Content />
    </MDXProvider>
  </MDXProvider>
</>
```

…which results in `h2`s using `Component3` and `h3`s using `Component4`.
No component is used for `h1`.

[context]: https://reactjs.org/docs/context.html

[start]: /docs/getting-started/

[what]: /docs/what-is-mdx/

[mdx-react]: /packages/react/

[mdx-preact]: /packages/preact/

[mdx-vue]: /packages/vue/

[options-provider-import-source]: /packages/mdx/#optionsproviderimportsource

[emotion]: /docs/getting-started/#emotion

[preact]: /docs/getting-started/#preact

[theme ui]: /docs/getting-started/#theme-ui

[vue]: /docs/getting-started/#vue

[toc]: /table-of-components/

[support]: /community/support/

[contribute]: /community/contribute/
