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.
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.
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.md#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.
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.md) and [translating](../../i18n/i18n-tutorial.md).
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:
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.md) 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.md#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.
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.
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:**
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:
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.
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.
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)).
- `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).