Skip to main content

MDX Plugins

unknown

MDX Plugins

CodeHarborHub uses MDX to power its documentation. Sometimes, you may want to extend or tweak Markdown syntax. For example:

  • Embed a YouTube video using image-like syntax: ![](https://youtu.be/example)
  • Style standalone links as social cards
  • Automatically prepend a copyright notice to every page

The answer is: create an MDX plugin!
MDX supports a powerful plugin system to customize how Markdown is parsed and transformed into JSX.

There are three common plugin use-cases:

How MDX Plugins Work

When Markdown is compiled, it goes through two intermediate steps:

  1. Markdown AST (MDAST)
  2. Hypertext AST (HAST)
  3. JSX Output

Plugins operate on these ASTs:

  • Remark → processes the Markdown AST
  • Rehype → processes the Hypertext AST
tip

Use plugins to introduce shorter syntax for frequently used JSX elements.
For example, CodeHarborHub’s admonition blocks are powered by a Remark plugin.

Default Plugins

Docusaurus automatically injects a set of default Remark plugins during Markdown processing.
These handle tasks such as:

  • Generating a Table of Contents
  • Adding anchor links to each heading
  • Transforming images and links to require() calls

These built-in plugins are great examples to inspire your own custom plugins.

Installing Plugins

An MDX plugin is usually an npm package, so install it like any other dependency.

Example: adding math support:

npm install --save remark-math@5 rehype-katex@6
Remark vs Rehype in action
  • remark-math extracts $...$ math expressions from Markdown and transforms them into a JSX placeholder.
  • rehype-katex then takes those placeholders and renders them into KaTeX-powered HTML.
warning

Many official Remark/Rehype plugins are ES Modules only. Docusaurus supports ESM, but we recommend using an ESM config file for easier imports.

Adding Plugins to docusaurus.config.js

Once installed, import and add the plugin to your config:

docusaurus.config.js
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';

export default {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
remarkPlugins: [remarkMath],
rehypePlugins: [rehypeKatex],
},
},
],
],
};

Using CommonJS? Dynamic imports make it work:

docusaurus.config.js
module.exports = async function createConfigAsync() {
return {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
remarkPlugins: [(await import('remark-math')).default],
rehypePlugins: [(await import('rehype-katex')).default],
},
},
],
],
};
};

Configuring Plugins

Some plugins accept custom options. Use [plugin, options] syntax:

docusaurus.config.js
import rehypeKatex from 'rehype-katex';

export default {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
rehypePlugins: [
[rehypeKatex, {strict: false}],
],
},
},
],
],
};

Check the plugin’s documentation for available options.

Creating Your Own Plugin

If no existing plugin fits your needs, you can create one. A plugin is a function that operates on the AST.

Example: prefix every h2 heading with Section X.

src/remark/section-prefix.js
import {visit} from 'unist-util-visit';

const plugin = () => {
return async (ast) => {
let count = 1;
visit(ast, 'heading', (node) => {
if (node.depth === 2 && node.children.length > 0) {
node.children.unshift({
type: 'text',
value: `Section ${count}. `,
});
count++;
}
});
};
};

export default plugin;

Import and register it:

docusaurus.config.js
import sectionPrefix from './src/remark/section-prefix';

export default {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
remarkPlugins: [sectionPrefix],
},
},
],
],
};
tip

The transformer function receives a second parameter, vfile, which provides metadata like the current Markdown file’s path.

Processing Order

By default, Docusaurus runs its internal plugins before your custom plugins. If you need to run your plugin first:

docusaurus.config.js
export default {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
beforeDefaultRemarkPlugins: [sectionPrefix],
},
},
],
],
};

This ensures your transformations (like heading prefixes) are included in generated tables of contents.