---
id: react
description: Using the power of React in Docusaurus Markdown documents, thanks to MDX
slug: /markdown-features/react
---

# MDX and React

```mdx-code-block
import BrowserWindow from '@site/src/components/BrowserWindow';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import styles from './markdown-features-react.module.css';
```

## Using JSX in Markdown {#using-jsx-in-markdown}

Docusaurus has built-in support for [MDX v1](https://mdxjs.com/), which allows you to write JSX within your Markdown files and render them as React components.

:::note

While Docusaurus parses both `.md` and `.mdx` files using MDX, some of the syntaxes are treated slightly differently by third-party tools. For the most accurate parsing and better editor support, we recommend using the `.mdx` extension for files containing MDX syntax.

:::

Check out the [MDX docs](https://mdxjs.com/) to see what other fancy stuff you can do with MDX.

### Exporting components {#exporting-components}

To define any custom component within an MDX file, you have to export it: only paragraphs that start with `export` will be parsed as components instead of prose.

```jsx
export const Highlight = ({children, color}) => (
  <span
    style={{
      backgroundColor: color,
      borderRadius: '2px',
      color: '#fff',
      padding: '0.2rem',
    }}>
    {children}
  </span>
);

<Highlight color="#25c2a0">Docusaurus green</Highlight> and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors.

I can write **Markdown** alongside my _JSX_!
```

Notice how it renders both the markup from your React component and the Markdown syntax:

```mdx-code-block
export const Highlight = ({children, color}) => (
  <span
    style={{
      backgroundColor: color,
      borderRadius: '2px',
      color: '#fff',
      padding: '0.2rem',
    }}>
    {children}
  </span>
);

<BrowserWindow minHeight={240}>

<Highlight color="#25c2a0">Docusaurus green</Highlight>
{` `}and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors.

I can write **Markdown** alongside my _JSX_!

</BrowserWindow>
```

:::caution MDX is JSX

Since all doc files are parsed using MDX, anything that looks like HTML is actually JSX. Therefore, if you need to inline-style a component, follow JSX flavor and provide style objects.

<!-- prettier-ignore -->
```jsx
/* Instead of this: */
<span style="background-color: red">Foo</span>
/* Use this: */
<span style={{backgroundColor: 'red'}}>Foo</span>
```

This behavior is different from Docusaurus 1. See also [Migrating from v1 to v2](../../migration/migration-manual.mdx#convert-style-attributes-to-style-objects-in-mdx).

In addition, MDX is not [100% compatible with CommonMark](https://github.com/facebook/docusaurus/issues/3018). Use the **[MDX playground](https://mdx-git-renovate-babel-monorepo-mdx.vercel.app/playground)** to ensure that your syntax is valid MDX.

:::

### Importing components {#importing-components}

You can also import your own components defined in other files or third-party components installed via npm.

<!-- prettier-ignore -->
```md
<!-- Docusaurus theme component -->
import TOCInline from '@theme/TOCInline';
<!-- External component -->
import Button from '@mui/material/Button';
<!-- Custom component -->
import BrowserWindow from '@site/src/components/BrowserWindow';
```

:::tip

The `@site` alias points to your website's directory, usually where the `docusaurus.config.js` file is. Using an alias instead of relative paths (`'../../src/components/BrowserWindow'`) saves you from updating import paths when moving files around, or when [versioning docs](../docs/versioning.mdx) and [translating](../../i18n/i18n-tutorial.mdx).

:::

While declaring components within Markdown is very convenient for simple cases, it becomes hard to maintain because of limited editor support, risks of parsing errors, and low reusability. Use a separate `.js` file when your component involves complex JS logic:

```jsx title="src/components/Highlight.js"
import React from 'react';

export default function Highlight({children, color}) {
  return (
    <span
      style={{
        backgroundColor: color,
        borderRadius: '2px',
        color: '#fff',
        padding: '0.2rem',
      }}>
      {children}
    </span>
  );
}
```

```md title="markdown-file.mdx"
import Highlight from '@site/src/components/Highlight';

<Highlight color="#25c2a0">Docusaurus green</Highlight>
```

:::tip

If you use the same component across a lot of files, you don't need to import it everywhere—consider adding it to the global scope. [See below](#mdx-component-scope)

:::

### MDX component scope {#mdx-component-scope}

Apart from [importing a component](#importing-components) and [exporting a component](#exporting-components), a third way to use a component in MDX is to **register it to the global scope**, which will make it automatically available in every MDX file, without any import statements.

For example, given this MDX file:

```md
- a
- list!

And some <highlight>custom markup</highlight>...
```

It will be compiled to a React component containing `ul`, `li`, `p`, and `highlight` tags. Now, you can optionally provide your own implementation for any of these tags in the form of React components. (`highlight` isn't even an intrinsic element: it needs an implementation!)

In Docusaurus, this MDX component scope is provided by the `@theme/MDXComponents` component. It's not a React component, _per se_, unlike most other exports under the `@theme/` alias: it is a record from tag names like `ul` and `img` to their custom implementations.

If you [swizzle](../../swizzling.mdx) this component, you will find all tags that have been re-implemented, and you can further customize our implementation by swizzling the respective sub-component, like `@theme/MDXComponents/Head` (which is used to implement the [`<head>`](./markdown-features-head-metadata.mdx) feature).

If you want to register extra tag names (like the `<highlight>` tag above), you should consider [wrapping `@theme/MDXComponents`](../../swizzling.mdx#wrapping), so you don't have to maintain all the existing mappings. Since the swizzle CLI doesn't allow wrapping non-component files yet, you should manually create the wrapper:

```js title="src/theme/MDXComponents.js"
import React from 'react';
// Import the original mapper
import MDXComponents from '@theme-original/MDXComponents';
// highlight-next-line
import Highlight from '@site/src/components/Highlight';

export default {
  // Re-use the default mapping
  ...MDXComponents,
  // Map the "highlight" tag to our <Highlight /> component!
  // `Highlight` will receive all props that were passed to `highlight` in MDX
  // highlight-next-line
  highlight: Highlight,
};
```

And now, you can freely use `<highlight>` in every page, without writing the import statement:

```md
I can conveniently use <highlight color="#25c2a0">Docusaurus green</highlight> everywhere!
```

```mdx-code-block
<BrowserWindow>

I can conveniently use <highlight color="#25c2a0">Docusaurus green</highlight> everywhere!

</BrowserWindow>
```

:::info

We use lower-case tag names like `highlight` to "pretend" that they are intrinsic elements, but you can use capitalized ones like `Highlight` as well.

:::

:::caution

This feature is powered by [a wrapper provider](https://mdx-git-renovate-babel-monorepo-mdx.vercel.app/advanced/components#mdxprovider). If you are importing Markdown in a React page, you have to supply this provider yourself through the `MDXContent` theme component.

```jsx title="src/pages/index.js"
import React from 'react';
import FeatureDisplay from './_featureDisplay.mdx';
// highlight-next-line
import MDXContent from '@theme/MDXContent';

export default function LandingPage() {
  return (
    <div>
      {/* highlight-start */}
      <MDXContent>
        <FeatureDisplay />
      </MDXContent>
      {/* highlight-end */}
    </div>
  );
}
```

If you don't wrap your imported MDX with `MDXContent`, the global scope will not be available.

:::

### Markdown and JSX interoperability {#markdown-and-jsx-interoperability}

Docusaurus v2 is using MDX v1, which has a lot of known cases where the content fails to be correctly parsed as Markdown. Use the **[MDX playground](https://mdx-git-renovate-babel-monorepo-mdx.vercel.app/playground)** to ensure that your syntax is valid MDX.

<details>
<summary>Samples of parsing failures</summary>

**A paragraph starting with a JSX tag will be seen entirely as a JSX string:**

```mdx-code-block
<Tabs groupId="jsx-and-md">
<TabItem value="Problem">
<div className={styles.wrappingBlock}>
```

```jsx
<span style={{color: 'red'}}>Highlighted text</span> but afterwards _Markdown_ **doesn't work**
```

```mdx-code-block
</div>
<div className={styles.wrappingBlock}>
<BrowserWindow>

<span style={{color: 'red'}}>Highlighted text</span> but afterwards _Markdown_ **doesn't work**

</BrowserWindow>
</div>
</TabItem>
<TabItem value="Workaround">

Use JSX for the rest of the line, or prefix the line with some plain text:

<div className={styles.wrappingBlock}>
```

```jsx
<span style={{color: 'red'}}>Use JSX for the paragraph</span> to stop <i>worrying about</i> <b>Markdown</b>

&#8203;<span style={{color: 'red'}}>← This is a zero-width space</span> and afterwards <i>Markdown</i> <b>works</b>
```

```mdx-code-block
</div>
<div className={styles.wrappingBlock}>
<BrowserWindow>

<span style={{color: 'red'}}>Use JSX for the paragraph</span> to stop <i>worrying about</i> <b>Markdown</b>

&#8203;<span style={{color: 'red'}}>← This is a zero-width space</span> and afterwards <i>Markdown</i> <b>works</b>

</BrowserWindow>
</div>
</TabItem>
</Tabs>

**Markdown within a JSX tag never works:**

<Tabs groupId="jsx-and-md">
<TabItem value="Problem">
<div className={styles.wrappingBlock}>
```

```jsx
<span style={{color: 'red'}}>**Bold doesn't work**</span>
```

```mdx-code-block
</div>
<div className={styles.wrappingBlock}>
<BrowserWindow>

<span style={{color: 'red'}}>**Bold doesn't work**</span>

</BrowserWindow>
</div>

</TabItem>
<TabItem value="Workaround">

Use JSX within JSX tag, or move the Markdown to the outer layer:

<div className={styles.wrappingBlock}>
```

```jsx
<span style={{color: 'red'}}><b>Bold now works</b></span>

**<span style={{color: 'red'}}>Bold now works</span>**
```

```mdx-code-block
</div>
<div className={styles.wrappingBlock}>
<BrowserWindow>

<span style={{color: 'red'}}><b>Bold now works</b></span>

**<span style={{color: 'red'}}>Bold now works</span>**

</BrowserWindow>
</div>
</TabItem>
</Tabs>

**Text immediately below a JSX tag will be seen as JSX text:**

<Tabs groupId="jsx-and-md">
<TabItem value="Problem">
<div className={styles.wrappingBlock}>
```

<!-- prettier-ignore -->
```jsx
<div style={{color: 'red'}}>
**Bold still doesn't work**
</div>
```

```mdx-code-block
</div>
<div className={styles.wrappingBlock}>
<BrowserWindow>

<div style={{color: 'red'}}>
**Bold still doesn't work**
</div>

</BrowserWindow>
</div>
</TabItem>
<TabItem value="Workaround">

Add an empty new line:

<div className={styles.wrappingBlock}>
```

<!-- prettier-ignore -->
```jsx
<div style={{color: 'red'}}>

**Bold now works**

</div>
```

```mdx-code-block
</div>
<div className={styles.wrappingBlock}>
<BrowserWindow>
<div style={{color: 'red'}}>

**Bold now works**

</div>
</BrowserWindow>
</div>
</TabItem>
</Tabs>

**Markdown text indented by four spaces will be seen as a code block:**

<Tabs groupId="jsx-and-md">
<TabItem value="Problem">
<div className={styles.wrappingBlock}>
```

<!-- prettier-ignore -->
```jsx
<div style={{color: 'red'}}>

    You may think I'm just some text...

</div>
```

```mdx-code-block
</div>
<div className={styles.wrappingBlock}>
<BrowserWindow>

<div style={{color: 'red'}}>

    You may think I'm just some text...

</div>

</BrowserWindow>
</div>
</TabItem>
<TabItem value="Workaround">

Don't indent:

<div className={styles.wrappingBlock}>
```

<!-- prettier-ignore -->
```jsx
<div style={{color: 'red'}}>

Now I'm actually just text

</div>
```

```mdx-code-block
</div>
<div className={styles.wrappingBlock}>
<BrowserWindow>
<div style={{color: 'red'}}>

Now I'm actually just text

</div>
</BrowserWindow>
</div>
</TabItem>
</Tabs>
```

</details>

## Importing code snippets {#importing-code-snippets}

You can not only import a file containing a component definition, but also import any code file as raw text, and then insert it in a code block, thanks to [Webpack raw-loader](https://webpack.js.org/loaders/raw-loader/). In order to use `raw-loader`, you first need to install it in your project:

```bash npm2yarn
npm install --save raw-loader
```

Now you can import code snippets from another file as it is:

<!-- prettier-ignore-start -->
```jsx title="myMarkdownFile.mdx"
import CodeBlock from '@theme/CodeBlock';
import MyComponentSource from '!!raw-loader!./myComponent';

<CodeBlock language="jsx">{MyComponentSource}</CodeBlock>
```
<!-- prettier-ignore-end -->

```mdx-code-block
import CodeBlock from '@theme/CodeBlock';
import MyComponentSource from '!!raw-loader!@site/src/pages/examples/_myComponent';

<BrowserWindow>

<CodeBlock language="jsx">{MyComponentSource}</CodeBlock>

</BrowserWindow>
```

See [using code blocks in JSX](./markdown-features-code-blocks.mdx#usage-in-jsx) for more details of the `<CodeBlock>` component.

:::note

You have to use `<CodeBlock>` rather than the Markdown triple-backtick ` ``` `, because the latter will ship out any of its content as-is, but you want to interpolate the imported text here.

:::

:::warning

This feature is experimental and might be subject to breaking API changes in the future.

:::

## Importing Markdown {#importing-markdown}

You can use Markdown files as components and import them elsewhere, either in Markdown files or in React pages.

By convention, using the **`_` filename prefix** will not create any doc page and means the Markdown file is a **"partial"**, to be imported by other files.

```md title="_markdown-partial-example.mdx"
<span>Hello {props.name}</span>

This is text some content from `_markdown-partial-example.mdx`.
```

<!-- prettier-ignore-start -->
```jsx title="someOtherDoc.mdx"
import PartialExample from './_markdown-partial-example.mdx';

<PartialExample name="Sebastien" />
```
<!-- prettier-ignore-end -->

```mdx-code-block
import PartialExample from './_markdown-partial-example.mdx';

<BrowserWindow>
  <PartialExample name="Sebastien" />
</BrowserWindow>
```

This way, you can reuse content among multiple pages and avoid duplicating materials.

:::caution

Currently, the table of contents does not contain the imported Markdown headings. This is a technical limitation that we are trying to solve ([issue](https://github.com/facebook/docusaurus/issues/3915)).

:::

## Available exports {#available-exports}

Within the MDX page, the following variables are available as globals:

- `frontMatter`: the front matter as a record of string keys and values;
- `toc`: the table of contents, as a tree of headings. See also [Inline TOC](./markdown-features-toc.mdx#inline-table-of-contents) for a more concrete use-case.
- `contentTitle`: the Markdown title, which is the first `h1` heading in the Markdown text. It's `undefined` if there isn't one (e.g. title specified in the front matter).

```jsx
import TOCInline from '@theme/TOCInline';
import CodeBlock from '@theme/CodeBlock';

The table of contents for this page, serialized:

<CodeBlock className="language-json">{JSON.stringify(toc, null, 2)}</CodeBlock>

The front matter of this page:

<ul>
  {Object.entries(frontMatter).map(([key, value]) => <li key={key}><b>{key}</b>: {value}</li>)}
</ul>

<p>The title of this page is: <b>{contentTitle}</b></p>
```

```mdx-code-block
import TOCInline from '@theme/TOCInline';

<BrowserWindow>

The table of contents for this page, serialized:

<CodeBlock className="language-json">{JSON.stringify(toc, null, 2)}</CodeBlock>

The front matter of this page:

<ul>
  {Object.entries(frontMatter).map(([key, value]) => <li key={key}><b>{key}</b>: {value}</li>)}
</ul>

<p>The title of this page is: <b>{contentTitle}</b></p>

</BrowserWindow>
```
