DEV Community

Alex Spinov
Alex Spinov

Posted on

MDX Has a Free API: Here's How to Build Interactive Documentation with React Components

What is MDX?

MDX lets you use JSX in your Markdown content. Write Markdown for your prose, and embed React components for interactive examples, charts, alerts — anything React can render.

MDX powers documentation at Vercel, Stripe, GitHub, and thousands of other companies. And its compiler API is completely free and open source.

The MDX Compiler API

MDX provides a programmatic API to compile .mdx files into JavaScript:

import { compile } from "@mdx-js/mdx";

const mdxContent = `
# Hello World

This is **MDX** with a React component:

<Counter initial={5} />
`;

const result = await compile(mdxContent);
console.log(String(result));
// Outputs compiled JavaScript with JSX
Enter fullscreen mode Exit fullscreen mode

Install

npm install @mdx-js/mdx @mdx-js/react
Enter fullscreen mode Exit fullscreen mode

Process MDX at Build Time

import { compile } from "@mdx-js/mdx";
import remarkGfm from "remark-gfm";
import rehypeHighlight from "rehype-highlight";

const compiled = await compile(mdxSource, {
  remarkPlugins: [remarkGfm],
  rehypePlugins: [rehypeHighlight],
  outputFormat: "function-body",
});
Enter fullscreen mode Exit fullscreen mode

The plugin ecosystem is massive:

  • remark-gfm: GitHub-flavored Markdown (tables, strikethrough)
  • rehype-highlight: Syntax highlighting
  • remark-math + rehype-katex: LaTeX math equations
  • rehype-autolink-headings: Auto-link headers

Evaluate MDX at Runtime

import { evaluate } from "@mdx-js/mdx";
import * as runtime from "react/jsx-runtime";

const { default: MDXContent } = await evaluate(
  "# Hello\n\nThis is *dynamic* MDX!",
  { ...runtime }
);

// Use in React:
// <MDXContent components={{ h1: MyCustomH1 }} />
Enter fullscreen mode Exit fullscreen mode

This is powerful for CMS-driven content where editors write MDX and you render it dynamically.

Custom Components

import { MDXProvider } from "@mdx-js/react";

const components = {
  h1: (props) => <h1 className="text-4xl font-bold" {...props} />,
  code: (props) => <code className="bg-gray-100 px-1 rounded" {...props} />,
  Callout: ({ type, children }) => (
    <div className={`callout callout-${type}`}>{children}</div>
  ),
  APIEndpoint: ({ method, path }) => (
    <div className="api-endpoint">
      <span className={`method-${method.toLowerCase()}`}>{method}</span>
      <code>{path}</code>
    </div>
  ),
};

export default function DocsLayout({ children }) {
  return <MDXProvider components={components}>{children}</MDXProvider>;
}
Enter fullscreen mode Exit fullscreen mode

Next.js Integration

// next.config.mjs
import createMDX from "@next/mdx";

const withMDX = createMDX({
  options: {
    remarkPlugins: [],
    rehypePlugins: [],
  },
});

export default withMDX({
  pageExtensions: ["js", "jsx", "mdx", "ts", "tsx"],
});
Enter fullscreen mode Exit fullscreen mode

Now any .mdx file in your app/ directory becomes a page:

// app/blog/hello/page.mdx
export const metadata = {
  title: "Hello World",
};

# Hello World

This page is written in MDX with **zero config**.

<InteractiveDemo />
Enter fullscreen mode Exit fullscreen mode

Extract Frontmatter

import { compile } from "@mdx-js/mdx";
import remarkFrontmatter from "remark-frontmatter";
import remarkMdxFrontmatter from "remark-mdx-frontmatter";

const result = await compile(source, {
  remarkPlugins: [
    remarkFrontmatter,
    [remarkMdxFrontmatter, { name: "metadata" }]
  ],
});
// Access metadata.title, metadata.date, etc.
Enter fullscreen mode Exit fullscreen mode

Real-World Use Case

A SaaS company rebuilt their docs with MDX:

  • Before: Static HTML, 200+ pages manually maintained
  • After: MDX + custom components, interactive API playground
  • Result: Support tickets dropped 40%, docs contribution PRs increased 3x

Need help building interactive documentation or developer tools?

📧 spinov001@gmail.com
🔧 My tools on Apify Store

Do you use MDX for docs? Share your setup in the comments!

Top comments (0)