Orientation
Content Processing
Search Infrastructure
Rendering and UI
Developer Tooling
How It Works
<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [packages/core/src/mdx-plugins/remark-structure.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-structure.ts)
- [packages/core/src/mdx-plugins/remark-steps.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-steps.ts)
- [packages/typescript/src/lib/remark-auto-type-table.ts](https://github.com/blade47/fumadocs/blob/main/packages/typescript/src/lib/remark-auto-type-table.ts)
- [packages/core/src/mdx-plugins/remark-llms.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-llms.ts)
- [packages/core/src/content/md.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/content/md.ts)
- [packages/core/src/mdx-plugins/remark-code-tab.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-code-tab.ts)
- [packages/core/src/mdx-plugins/remark-block-id.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-block-id.ts)
- [packages/obsidian/src/mdx/index.ts](https://github.com/blade47/fumadocs/blob/main/packages/obsidian/src/mdx/index.ts)
- [packages/core/src/mdx-plugins/rehype-code.core.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/rehype-code.core.ts)
- [packages/mdx/src/loaders/mdx/remark-postprocess.ts](https://github.com/blade47/fumadocs/blob/main/packages/mdx/src/loaders/mdx/remark-postprocess.ts)
- [packages/core/src/mdx-plugins/rehype-toc.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/rehype-toc.ts)
- [packages/mdx/src/loaders/mdx/remark-include.ts](https://github.com/blade47/fumadocs/blob/main/packages/mdx/src/loaders/mdx/remark-include.ts)
- [packages/core/src/mdx-plugins/remark-feedback-block.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-feedback-block.ts)
- [packages/core/src/mdx-plugins/remark-mdx-files.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-mdx-files.ts)
- [packages/core/src/mdx-plugins/remark-admonition.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-admonition.ts)
- [packages/core/src/mdx-plugins/remark-npm.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-npm.ts)
- [packages/core/src/mdx-plugins/remark-heading.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-heading.ts)
- [packages/obsidian/src/remark/remark-block-id.ts](https://github.com/blade47/fumadocs/blob/main/packages/obsidian/src/remark/remark-block-id.ts)
- [packages/core/src/mdx-plugins/index.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/index.ts)
- [packages/core/src/content/mdx/preset-runtime.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/content/mdx/preset-runtime.ts)
- [packages/core/src/mdx-plugins/rehype-code/parsers.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/rehype-code/parsers.ts)
- [packages/obsidian/src/remark/remark-wikilinks.ts](https://github.com/blade47/fumadocs/blob/main/packages/obsidian/src/remark/remark-wikilinks.ts)
- [packages/core/src/content/mdx/preset-bundler.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/content/mdx/preset-bundler.ts)
- [packages/core/src/mdx-plugins/remark-llms.runtime.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-llms.runtime.ts)
- [packages/doc-gen/src/remark-install.ts](https://github.com/blade47/fumadocs/blob/main/packages/doc-gen/src/remark-install.ts)
- [packages/preview/src/lib/md.ts](https://github.com/blade47/fumadocs/blob/main/packages/preview/src/lib/md.ts)
- [packages/core/src/mdx-plugins/remark-mdx-mermaid.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-mdx-mermaid.ts)
- [packages/mdx/src/core.ts](https://github.com/blade47/fumadocs/blob/main/packages/mdx/src/core.ts)
- [packages/core/src/mdx-plugins/stringifier.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/stringifier.ts)
- [packages/content-collections/src/configuration.ts](https://github.com/blade47/fumadocs/blob/main/packages/content-collections/src/configuration.ts)
</details>
MDX Plugins act as the foundational processing layer within the Fumadocs documentation ecosystem, sitting directly atop the `unified`, `remark`, and `rehype` infrastructure. Their purpose is to augment standard Markdown and MDX documents with domain-specific features required for technical documentation, such as automated structure extraction, advanced code block handling, and syntax enrichment for complex UI elements like tabbed code blocks, file trees, and admonitions.
By operating as standard plugins for the `unified` ecosystem, they enable a modular pipeline architecture where each plugin performs a targeted transformation on the Abstract Syntax Tree (AST). This design decouples documentation business logic from core parsing, allowing developers to opt-in to specific capabilities like automatic TOC generation, type table insertion for TypeScript interfaces, or Obsidian-style wikilinks.
The subsystem interacts heavily with the file system during build-time via loaders and content-collections to resolve imports, glob patterns, and frontmatter. At its core, the plugin system prioritizes predictability and performance by transforming the AST during the compilation lifecycle, ensuring that the heavy lifting—such as static code analysis for type tables or AST restructuring for tabs—happens once during build/bundle time, rather than at runtime.
## Core Transformation Pipeline
The MDX processor relies on a sequence of plugins that transform the document state from raw text into a rich component representation. The pipeline consists of two primary stages: Remark (Markdown AST) and Rehype (HTML AST).
\`\`\`mermaid
flowchart TD
A["Raw Markdown/MDX"] --> B["Remark Processors<br>(AST Manipulation)"]
B --> C["remark-gfm, remark-heading, etc."]
C --> D["Rehype Processors<br>(HTML/JSX Transformation)"]
D --> E["rehype-code, rehype-toc"]
E --> F["Final JSX Runtime Output"]
\`\`\`
Sources: [packages/core/src/content/mdx/preset-bundler.ts:38-76](https://github.com/blade47/fumadocs/blob/main/packages/content-collections/src/configuration.ts#L38-L76), [packages/core/src/content/mdx/preset-runtime.ts:35-76](https://github.com/blade47/fumadocs/blob/main/packages/core/src/content/mdx/preset-runtime.ts#L35-L76)
The order of plugin registration is critical. Because plugins like `remarkStructure` and `remarkHeading` depend on the ID properties generated during the heading pass, they must be registered in the correct sequence. The presets (`preset-runtime.ts` and `preset-bundler.ts`) enforce this ordering to maintain invariant consistency across the transformation chain.
## Code Block Transformation Mechanism
The code block subsystem utilizes a specialized transformer approach to convert standard fenced code blocks into enriched JSX components. It leverages Shiki for syntax highlighting while injecting complex functionality like tabs, icons, and line numbering through specialized `ShikiTransformer` instances created in `rehype-code.core.ts`.
- **Parsing Phase**: The system intercepts the document tree and delegates to the highlighter to generate the highlighted HAST (HTML Abstract Syntax Tree).
- **Transformation Phase**: During the processing step, it injects the transformer suite.
- **Enrichment**: The `transformerTab` function adds logic to identify if a code block should be wrapped into a `<Tab>` component based on meta-string metadata.
\`\`\`mermaid
sequenceDiagram
participant P as Code Processor
participant S as Shiki Highlighter
participant T as Transformers (Icon/Tab/Diff)
P->>S: getOrInit()
P->>T: initTransformer()
P->>S: loadLanguage() / loadTheme()
S-->>P: Ready
P->>P: rehypeShikiFromHighlighter(tree, transformers)
\`\`\`
Sources: [packages/core/src/mdx-plugins/rehype-code.core.ts:82-142](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/rehype-code.core.ts#L82-L142)
> [!WARNING]
> When using `tab="value"` in code blocks, you must ensure `remarkCodeTab` is configured in the pipeline. Using the legacy approach in the rehype pipeline (via `transformerTab`) will trigger a warning, as that path is deprecated in favor of the more robust `remarkCodeTab` transformation logic.
## Tabulated Data: Plugin Selection and Priority
Plugins often perform complex lookups to determine how to process a specific block. The following table summarizes key plugins that employ prioritization logic:
| Plugin | Selection Logic | Tie-break / Priority |
| :--- | :--- | :--- |
| `remarkCodeTab` | Checks for `tab` or `tab-group` metadata | Sequence order in parent node children |
| `remarkSteps` | Checks `data-fd-step` existence | `currentStep` incrementer |
| `rehypeToc` | `HeadingTags` (h1-h6) | Document index order |
| `remarkStructure` | Configured `types` array | Depth-first search (visit) |
Sources: [packages/core/src/mdx-plugins/remark-code-tab.ts:248-268](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-code-tab.ts#L248-L268), [packages/core/src/mdx-plugins/remark-steps.ts:110-133](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-steps.ts#L110-L133), [packages/core/src/mdx-plugins/rehype-toc.ts:70-108](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/rehype-toc.ts#L70-L108)
## Step Processing Mechanism
The `remarkSteps` plugin converts headings into interactive step components by transforming consecutive headings of the same depth into a single `mdxJsxFlowElement` container.
1. **Iteration**: It visits every node and identifies headings.
2. **Identification**: It uses `handleHeadingStep` to check if a heading matches the regex `/^(\d+)\.\s(.+)$/` or carries the `[step]` tag.
3. **Encapsulation**: When a block of steps is found, `convertToSteps` is called to group them into a `fd-steps` div, mapping children into `fd-step` containers.
> [!IMPORTANT]
> The `remarkSteps` plugin requires a strict invariant: if a heading depth changes within a detected block, the `onEnd()` function is triggered immediately, effectively closing the current step group. This prevents deeply nested or mismatched headings from being incorrectly captured.
Sources: [packages/core/src/mdx-plugins/remark-steps.ts:100-133](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-steps.ts#L100-L133)
## Stringification and Context Handling
The `defaultStringifier` provides a unified way to turn MDAST nodes back into plain text, which is vital for search indexing, LLM context generation, and structured data extraction. It wraps the `mdast-util-to-markdown` utility and adds context-aware handler support.
- **Handlers**: These allow customization of how nodes (e.g., `link`, `heading`, `image`) are converted to strings.
- **Context Injection**: By utilizing a provided `Context` type, the stringifier allows custom handlers (e.g., in `remark-structure`) to relay metadata (like `addContent`) during the traversal of the syntax tree.
Sources: [packages/core/src/mdx-plugins/stringifier.ts:237-257](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/stringifier.ts#L237-L257)
## Design Trade-offs
| Design Choice | Benefit | Cost |
| :--- | :--- | :--- |
| **AST Transformation** | High performance, build-time static generation | Complex plugin order dependencies |
| **Unified Handlers** | Consistent output for different use cases | Handler pollution (logic spread across multiple plugins) |
| **MDX Custom Element Injection** | Enables rich UI components in documentation | Requires MDX compiler support (or `unified` plugin intervention) |
Sources: [packages/core/src/mdx-plugins/stringifier.ts:116-174](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/stringifier.ts#L116-L174), [packages/core/src/mdx-plugins/remark-structure.ts:152-199](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-structure.ts#L152-L199)
## Full Worked Example: Generating Structured Data
This snippet shows how a manual call to `structure` (an export of `remarkStructure`) processes content into a structured data object.
\`\`\`typescript
import { structure } from 'fumadocs-core/mdx-plugins/remark-structure';
const content = `
# Getting Started
This is the intro.
## Installation
Run \`npm install\`.
`;
const data = structure(content);
// Returns:
// {
// headings: [{ id: 'getting-started', content: 'Getting Started' }, ...],
// contents: [{ heading: 'getting-started', content: 'This is the intro.' }, ...]
// }
\`\`\`
Sources: [packages/core/src/mdx-plugins/remark-structure.ts:216-229](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/remark-structure.ts#L216-L229)
</Tab>
## Related
- [MDX Bundling](/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/content-engine/mdx-bundling)