Skip to main content

Docusaurus Markdown & MDX Formatting Guidelines

These guidelines are tailored for a documentation site where most content consists of code blocks and quick-reference snippets. All recommendations are based on the official Docusaurus documentation and established best practices.


1. Choose .md vs .mdx (When to Use MDX)

  • Use the .mdx extension whenever you need any of the following features: Tabs, Admonitions, Mermaid diagrams, embedded React components, or advanced code features like <CodeBlock> and importing code as raw text. See MDX & React.
  • MDX is strict. If Prettier causes formatting issues, you can add a /* prettier-ignore */ comment above the problematic block or exclude *.mdx files from Prettier formatting.

2. Headings & Table of Contents

  • Each page should have only one H1 heading (#), which serves as the document title. Main sections should begin with an H2 heading (##).
  • Each heading automatically gets an ID based on its text. For stable anchor links, you should set an explicit ID:
    ### Installation Steps {#installation-steps}
    You can then link to it using [see here](#installation-steps).
    Source: Headings & TOC
  • The Table of Contents (TOC) defaults to including headings from h2 to h3. You can adjust this range on a per-page basis using front matter or globally in the theme configuration.
---
toc_min_heading_level: 2
toc_max_heading_level: 5
---
// docusaurus.config.js
export default {
themeConfig: {
tableOfContents: { minHeadingLevel: 2, maxHeadingLevel: 5 },
},
};

References: Headings & TOC, Theme configuration

Prefer relative file-path links (including the .md or .mdx extension) when linking between documents. Docusaurus automatically converts these paths into final URL routes, ensuring they remain correct across different versions and locales.

  • Examples (from docs/folder/doc1.mdx):
I am referencing a [document](doc2.mdx).
This one is [in a subfolder](subfolder/doc3.mdx).
This link goes [across folders](../otherFolder/doc4.mdx).

Avoid hard-coded absolute URL paths like /docs/..., as they are not portable. Source: Markdown links

4. Images, Files, and Assets

  • Co-locate assets with your Markdown files when it's convenient:
/website/docs/myFeature.mdx
/website/docs/assets/docusaurus-asset-example-banner.png
/website/docs/assets/docusaurus-asset-example.docx
  • Images can be embedded using standard Markdown, require, or an import statement:
![Example banner](./assets/docusaurus-asset-example-banner.png)
<img
src={require("./assets/docusaurus-asset-example-banner.png").default}
alt="Example banner"
/>
import myImageUrl from "./assets/docusaurus-asset-example-banner.png";
<img src={myImageUrl} alt="Example banner" />;
  • Link to downloadable files using standard Markdown syntax:
[Download this docx](./assets/docusaurus-asset-example.docx)
  • Absolute paths resolve from your static directories: ![Logo](/img/docusaurus.png)
  • To bypass asset processing and use a raw URL path, prefix it with pathname:///:
    ![banner](pathname:///img/banner.png)
    Source: Assets

Note: Some users report issues with reference-style image links. Inline Markdown or JSX forms are the most reliable methods in Docusaurus.

5. Code Blocks — Core Practices

Use fenced code blocks with language tags and enhance them with Docusaurus features.

a) Basic Fenced Blocks

Always specify the language for syntax highlighting.

console.log("Hello, Docusaurus!");

Source: Code blocks

b) Code Titles

Use a title attribute to add a descriptive header, such as a file path.

/src/components/HelloCodeTitle.js
function HelloCodeTitle(props) {
return <h1>Hello, {props.name}</h1>;
}

c) Line Numbering

Add the showLineNumbers attribute to display line numbers.

export default function Example() {
return <div>Hello</div>;
}

d) Line Highlighting

You can highlight specific lines using either metadata in curly braces or "magic comments."

  • Metadata Ranges (good for short, stable snippets):
import React from "react";

function MyComponent(props) {
if (props.isBar) {
return <div>Bar</div>;
}
return <div>Foo</div>;
}
  • Magic Comments (great for snippets that mirror evolving source code):
function doThing(flag) {
if (flag) {
return "highlighted";
}
return "plain";
}
  • You can customize magic comments and their styles via the theme configuration and custom CSS:
// docusaurus.config.js
export default {
themeConfig: {
prism: {
magicComments: [
{
className: "theme-code-block-highlighted-line",
line: "highlight-next-line",
block: { start: "highlight-start", end: "highlight-end" },
},
{ className: "code-block-error-line", line: "This will error" },
],
},
},
};
/* custom.css */
:root {
--docusaurus-highlighted-code-line-bg: rgb(72, 77, 91);
}
[data-theme="dark"] {
--docusaurus-highlighted-code-line-bg: rgb(100, 100, 100);
}
.code-block-error-line {
background-color: #ff000020;
border-left: 3px solid #ff000080;
}

References: Code blocks

e) Syntax Highlighting Themes (Prism)

  • The default theme is Palenight. You can switch themes and add support for more languages in docusaurus.config.js.
// docusaurus.config.js
import { prismThemes } from "prism-react-renderer";

export default {
themeConfig: {
prism: {
theme: prismThemes.dracula,
// darkTheme: prismThemes.dracula, // Optional: specify a different theme for dark mode
additionalLanguages: ["powershell", "csharp", "java"],
},
},
};

References: Code blocks, Theme configuration

f) Multi-Language Examples with Tabs

Use Tabs to present code in different languages (e.g., JS/TS) or for different platforms (e.g., macOS/Windows/Linux).

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

<Tabs groupId="operating-systems" defaultValue="mac" queryString="os">
<TabItem value="mac" label="macOS">
```bash
brew install my-tool
```
</TabItem>
<TabItem value="win" label="Windows">
```powershell
choco install my-tool
```
</TabItem>
<TabItem value="linux" label="Linux">
```bash
sudo apt-get install my-tool
```
</TabItem
</Tabs>

References: Tabs

g) Automatic npm/yarn/pnpm Tabs

Use the npm2yarn remark plugin to automatically transform npm install commands into a set of tabs for npm, yarn, and pnpm.

npm install @docusaurus/remark-plugin-npm2yarn
// docusaurus.config.js
remarkPlugins: [
[require("@docusaurus/remark-plugin-npm2yarn"), { sync: true }],
];

Reference: Code blocks → npm2yarn

h) Live, Editable Code Blocks

Install and enable the live code block theme, then use the live language identifier on a code block.

npm install @docusaurus/theme-live-codeblock
function Clock() {
const [date, setDate] = React.useState(new Date());
React.useEffect(() => {
const id = setInterval(() => setDate(new Date()), 1000);
return () => clearInterval(id);
}, []);
return <h2>{date.toLocaleTimeString()}</h2>;
}

Reference: Code blocks → Interactive code editor

i) Import Code from Files (DRY Principle)

Use MDX with the @theme/CodeBlock component and raw-loader to keep documentation in sync with your source code.

npm install --save-dev raw-loader
import CodeBlock from "@theme/CodeBlock";
import ComponentSource from "!!raw-loader!./_my-component.tsx";

<CodeBlock language="tsx" title="/src/components/MyComponent.tsx">
{ComponentSource}
</CodeBlock>

Reference: MDX & React → Importing code snippets

6. Tabs — Conventions and Best Practices

  • Default Tab: Add the default prop to a TabItem or set the defaultValue prop on the parent Tabs component.
  • Syncing: Use the same groupId to sync the selected tab across multiple tab groups on the same page.
  • Persist in URL: Add a queryString prop to Tabs to sync the selection with a URL query parameter.
  • Performance: For pages with many tabs, use <Tabs lazy /> to render only the active tab's content on the initial page load.

Source: Tabs

7. Admonitions — Callouts for Notes and Warnings

  • Use triple-colon syntax with a type: note, tip, info, warning, or danger.
:::tip[Quick Tip]
Use line highlighting to draw attention to critical lines in your code snippets.
:::
  • Prettier: Keep blank lines before and after admonitions to prevent auto-formatting from breaking the syntax.
  • Nesting: You can nest admonitions by adding more colons (::::).
  • MDX: Admonitions work in .mdx files, and you can even place other components like Tabs inside them.

Source: Admonitions

8. Diagrams with Mermaid (Optional)

  • First, enable the Mermaid theme:
npm install @docusaurus/theme-mermaid
// docusaurus.config.js
export default {
markdown: { mermaid: true },
themes: ["@docusaurus/theme-mermaid"],
};
  • Use a fenced code block with the mermaid language identifier:
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;

Source: Diagrams

9. Math Equations with KaTeX (Optional)

  • Install and enable the required remark/rehype plugins:
npm install remark-math@6 rehype-katex@7
// docusaurus.config.js
import remarkMath from "remark-math";
import rehypeKatex from "rehype-katex";

export default {
presets: [
[
"@docusaurus/preset-classic",
{ docs: { remarkPlugins: [remarkMath], rehypePlugins: [rehypeKatex] } },
],
],
stylesheets: [
{
href: "https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css",
type: "text/css",
integrity:
"sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM",
crossorigin: "anonymous",
},
],
};
  • Inline math: $f(x)=x^2$
  • Block math:
$$
I = \int_0^{2\pi} \sin(x)\,dx
$$

Source: Math equations

10. Opinionated Style Guide

  • Prefer short, focused snippets. Add a title with the absolute repository path to aid in searching:
    title="/app/services/payments/createCharge.ts"
  • When mirroring real code, use magic comments for highlighting, as they are more maintainable than line numbers.
  • Use showLineNumbers for snippets longer than 10-15 lines.
  • For command-line instructions, use bash or powershell and enable npm2yarn for consistency.
  • For OS- or language-specific instructions, always use Tabs with a shared groupId.
  • Use admonitions to highlight important caveats (e.g., "Requires Node 20+", "macOS only", "Experimental feature").
  • Add explicit heading IDs ({#custom-id}) to create stable deep links.
  • Co-locate assets next to your documents and use standard Markdown image syntax for simplicity.

11. Copy-Paste Snippets

Prism Theme and Additional Languages

// docusaurus.config.js
import { prismThemes } from "prism-react-renderer";

export default {
themeConfig: {
prism: {
theme: prismThemes.dracula,
additionalLanguages: ["powershell", "csharp", "bash"],
},
},
};

Synced Tabs with URL Persistence

<Tabs groupId="os" defaultValue="mac" queryString="os">
<TabItem value="mac" label="macOS" default>
```bash brew install my-tool ```
</TabItem>
<TabItem value="win" label="Windows">
```powershell choco install my-tool ```
</TabItem>
<TabItem value="linux" label="Linux">
```bash sudo apt-get install my-tool ```
</TabItem>
</Tabs>

Admonition with Nested Tabs

:::warning[Breaking Change in v3.0]

The CLI flags have changed. Please use the correct flag for your operating system.

<Tabs groupId="os">
<TabItem value="mac" label="macOS">
Use the `--darwin` flag.
</TabItem>
<TabItem value="win" label="Windows">
Use the `--windows` flag.
</TabItem>
</Tabs>

:::