How to Add Custom MDX Components to Docusaurus Pages
You add custom MDX components to Docusaurus by creating a src/theme/MDXComponents.tsx file that imports and wraps the default component map from @theme-original/MDXComponents, allowing you to register custom React components that become globally available in every MDX file without requiring imports.
Docusaurus renders every .mdx file inside an MDXProvider that relies on a component mapping system to translate custom JSX tags into React components. According to the facebook/docusaurus source code, this mapping lives in @theme/MDXComponents and is implemented at packages/docusaurus-theme-classic/src/theme/MDXComponents/index.tsx. By wrapping this default export rather than editing it directly, you can extend the global MDX scope with your own interactive elements while preserving upstream compatibility.
Understanding the MDX Provider Architecture
The MDXContent component (packages/docusaurus-theme-classic/src/theme/MDXContent/index.tsx) serves as the entry point for all MDX pages. It wraps content in an MDXProvider and passes a component map that tells MDX how to resolve tags like <Highlight> or <Tabs>.
The default component map resides in packages/docusaurus-theme-classic/src/theme/MDXComponents/index.tsx. Docusaurus uses a theme-resolution algorithm that automatically prefers user-provided files over built-in theme files, meaning any file you create at src/theme/MDXComponents.{js,tsx} will override the default without modifying node_modules.
Creating a Custom React Component
First, build the React component you want to expose to MDX. Store it in your project's src/components directory.
import React from 'react';
import clsx from 'clsx';
import styles from './Highlight.module.css';
export default function Highlight({
children,
color = '#ff0',
}: {
children: React.ReactNode;
color?: string;
}) {
return (
<span className={clsx(styles.highlight)} style={{backgroundColor: color}}>
{children}
</span>
);
}
Save this as src/components/Highlight.tsx. This component accepts children and an optional color prop, rendering a styled span element.
Wrapping the Default MDX Component Map
Instead of swizzling the theme (which copies the original file and risks divergence from future Docusaurus releases), you should wrap the default mapping. Create a new file at src/theme/MDXComponents.tsx:
import React from 'react';
// Import the original mapping supplied by the classic theme
import MDXComponents from '@theme-original/MDXComponents';
// Import the custom component you just created
import Highlight from '@site/src/components/Highlight';
// Export a new map that merges the original with your additions
export default {
// Keep all built-in mappings (Tabs, Details, etc.)
...MDXComponents,
// Register the custom tag <Highlight>
Highlight,
};
This pattern—explicitly documented in website/docs/guides/markdown-features/markdown-features-react.mdx at lines 68-82—preserves all default Docusaurus MDX components while adding your custom entries to the global scope.
Using Custom Components in MDX Files
Once registered in MDXComponents.tsx, your component is available in any .mdx file throughout your site without import statements:
# My Awesome Page
Here is a highlighted word: <Highlight color="#25c2a0">Docusaurus green</Highlight>.
And here is default highlighting: <Highlight>Yellow highlight</Highlight>.
The MDX compiler automatically resolves the <Highlight> tag to your React component via the provider's component map.
Advanced: Manual MDXProvider Usage
If you need to render MDX content inside a pure React page (for example, when importing an MDX file into a custom page component), wrap it with MDXContent to ensure the component map is available:
import React from 'react';
import MDXContent from '@theme/MDXContent';
import MyMdxPage from './my-page.mdx';
export default function Wrapper() {
return (
<MDXContent>
<MyMdxPage />
</MDXContent>
);
}
As noted in the official guide (lines 99-107 of markdown-features-react.mdx), this ensures your custom components and all default Docusaurus MDX components resolve correctly in non-standard rendering contexts.
Summary
- Create
src/theme/MDXComponents.tsxin your project to extend the global MDX component map. - Import the original mapping using
@theme-original/MDXComponentsto preserve default components likeTabsandDetails. - Spread the original components and append your custom React components to make them globally available.
- Avoid swizzling
@theme/MDXComponentsto prevent merge conflicts when upgrading Docusaurus versions. - Use custom tags directly in any
.mdxfile without import statements once registered.
Frequently Asked Questions
What is the difference between wrapping and swizzling MDXComponents?
Swizzling copies the entire MDXComponents source from packages/docusaurus-theme-classic/src/theme/MDXComponents/index.tsx into your project, making you responsible for maintaining that code through Docusaurus updates. Wrapping imports the original via @theme-original/MDXComponents and exports a modified version, ensuring you receive upstream bug fixes and new features automatically while only managing your additive changes.
Can I override default Docusaurus MDX components like Tabs or Details?
Yes. When you spread ...MDXComponents into your exported object, you can overwrite specific keys. For example, adding Details: MyCustomDetails after the spread will replace the default collapsible details component with your implementation across all MDX files.
Do I need to import custom components in every MDX file?
No. Once you register a component in src/theme/MDXComponents.tsx, it becomes part of the global MDX scope provided by the MDXProvider. You can use the component immediately in any .mdx file without import statements, as the tag is resolved automatically during the MDX compilation process.
How do I use MDX components in pure React pages?
Import the MDXContent component from @theme/MDXContent and wrap your imported MDX content with it. This ensures the component map—including your custom registrations—is injected into the React tree, allowing MDX tags to resolve correctly even outside of standard documentation pages.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →