MDX and React
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';Docusaurus has built-in support for MDX, which allows you to write JSX within your Markdown files and render them as React components.
Check out the MDX docs to see what fancy stuff you can do with MDX.
Exporting components
Section titled “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.
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:
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>Importing components
Section titled “Importing components”You can also import your own components defined in other files or third-party components installed via npm.
<!-- 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';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:
import React from 'react';
export default function Highlight({children, color}) {
return (
<span
style={{
backgroundColor: color,
borderRadius: '2px',
color: '#fff',
padding: '0.2rem',
}}>
{children}
</span>
);
}import Highlight from '@site/src/components/Highlight';
<Highlight color="#25c2a0">Docusaurus green</Highlight>MDX component scope
Section titled “MDX component scope”Apart from importing a component and exporting a component, 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:
- a
- list!
And some <Highlight>custom markup</Highlight>...It will be compiled to a React component containing ul, li, p, and Highlight elements. Highlight is not a native html element: you need to provide your own React component implementation for it.
In Docusaurus, the MDX component scope is provided by the @theme/MDXComponents file. It's not a React component, per se, unlike most other exports under the @theme/ alias: it is a record from tag names like Highlight to their React component implementations.
If you swizzle this component, you will find all tags that have been implemented, and you can further customize our implementation by swizzling the respective sub-component, like @theme/MDXComponents/Code (which is used to render Markdown code blocks).
If you want to register extra tag names (like the <Highlight> tag above), you should consider wrapping @theme/MDXComponents, 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:
import React from 'react';// Import the original mapperimport MDXComponents from '@theme-original/MDXComponents';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,};And now, you can freely use <Highlight> in every page, without writing the import statement:
I can conveniently use <Highlight color="#25c2a0">Docusaurus green</Highlight> everywhere!<BrowserWindow>
I can conveniently use <Highlight color="#25c2a0">Docusaurus green</Highlight> everywhere!
</BrowserWindow>Markdown and JSX interoperability
Section titled “Markdown and JSX interoperability”Docusaurus v3 is using MDX v3.
The MDX syntax is mostly compatible with CommonMark, but is much stricter because your .mdx files can use JSX and are compiled into real React components (check the playground).
Some valid CommonMark features won't work with MDX (more info), notably:
- Indented code blocks: use triple backticks instead
- Autolinks (
<http://localhost:3000>): use regular link syntax instead ([http://localhost:3000](http://localhost:3000)) - HTML syntax (
<p style="color: red;">): use JSX instead (<p style={{color: 'red'}}>) - Unescaped
{and<: escape them with\instead (\{and\<)
Importing code snippets
Section titled “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 the standard import attributes syntax:
import CodeBlock from '@theme/CodeBlock';
import MyComponentSource from './myComponent.js' with {type: 'text'};
<CodeBlock language="jsx">{MyComponentSource}</CodeBlock>import CodeBlock from '@theme/CodeBlock';
import MyComponentSource from '@site/src/pages/examples/_myComponent.tsx' with {type: 'text'};
<BrowserWindow>
<CodeBlock language="jsx">{MyComponentSource}</CodeBlock>
</BrowserWindow>See using code blocks in JSX for more details of the <CodeBlock> component.
Importing Markdown
Section titled “Importing Markdown”You can use Markdown files as components and import them elsewhere, either in Markdown files or in React pages. Each MDX file default-exports its page content as a React component. In the import statement, you can default-import this component with any name, but it must be capitalized following React's naming rules.
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.
<span>Hello {props.name}</span>
This is text some content from `_markdown-partial-example.mdx`.import PartialExample from './_markdown-partial-example.mdx';
<PartialExample name="Sebastien" />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.
Available exports
Section titled “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 for a more concrete use-case.contentTitle: the Markdown title, which is the firsth1heading in the Markdown text. It'sundefinedif there isn't one (e.g. title specified in the front matter).
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>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>