@md2docx/jsx
v1.0.0
Published
A modern, SSR-friendly React Markdown renderer that preserves the MDAST tree for reuse (e.g., mdast2docx), supports full JSX children, unified plugins, and component overrides.
Maintainers
Keywords
Readme
MDX Renderer [@m2d/react-markdown]
✨ A modern, SSR-compatible Markdown renderer for React with full MDAST/HAST access — built for customization, performance, and document generation - docx/pdf.
🔥 Why @m2d/react-markdown?
@m2d/react-markdown goes beyond traditional React Markdown libraries by focusing on:
- ✅ Server-side rendering (SSR) without hooks
- ✅ Full JSX children support (not just strings)
- ✅ Access to raw MDAST & HAST trees
- ✅ Drop-in plugin support via Unified (
remark,rehype, etc.) - ✅ Custom component overrides per tag
- ✅ Integration with tools like
mdast2docx
Compared to react-markdown, this library offers:
| Feature | @m2d/react-markdown ✅ | react-markdown ❌ |
| -------------------------------------- | ------------------------ | ------------------- |
| Full JSX support (not just strings) | ✅ | ❌ |
| SSR-safe (no hooks) | ✅ | ✅ |
| Client Side component with memoization | ✅ | ❌ |
| MDAST + HAST access via astRef | ✅ | ❌ |
| Component-level overrides | ✅ | ✅ |
| Unified plugin support | ✅ | ✅ |
| Tiny bundle (minzipped) | ~35 kB | ~45 kB |
| Built-in DOCX-friendly AST output | ✅ | ❌ |
📦 Installation
pnpm add @m2d/react-markdownor
npm install @m2d/react-markdownor
yarn add @m2d/react-markdown🚀 Server vs Client
By default, this package is SSR-safe and has no client-specific hooks.
✅ Server (default):
import { Md } from "@m2d/react-markdown";🔁 Client (for dynamic reactivity/memoization):
import { Md } from "@m2d/react-markdown/client";This version supports client-side behavior with memoization and dynamic JSX rendering.
⚡ Example: Rendering + Exporting DOCX
import { Md } from "@m2d/react-markdown/client";
import { toDocx } from "mdast2docx";
import { useRef } from "react";
const astRef = useRef([]);
export default function Page() {
return (
<>
<Md astRef={astRef}>{`# Hello\n\nThis is **Markdown**.`}</Md>
<button
onClick={() => {
const doc = toDocx(astRef.current[0].mdast);
// Save or download doc
}}>
Export to DOCX
</button>
</>
);
}Note for Server Component use you can replace useRef with custom ref object
const astRef = {current: undefined} as AstRef
🧠 JSX-Aware Parsing
Unlike most markdown renderers, @m2d/react-markdown supports arbitrary JSX as children:
import { Mdx } from "@m2d/react-markdown/server";
// ...
<Mdx>
<article>{"# Markdown Heading\n\nSome **rich** content."}</article>
</Mdx>;
astRef.currentis an array — one per Markdown string — each with{ mdast, hast }. The default<Md>export accepts only string children for better optimization.
🎨 Component Overrides
import { Md } from "@m2d/react-markdown";
import { Unwrap, Omit } from "@m2d/react-markdown/server";
<Md
components={{
em: Unwrap,
blockquote: Omit,
code: props => <CodeBlock {...props} />,
}}>
{`*em is unwrapped*\n\n> blockquote is removed`}
</Md>;Use the built-in helpers:
Unwrap– renders only childrenOmit– removes element and content entirelyCodeBlock- it is your custom component
🔌 Plugin Support (Unified)
Use any remark or rehype plugin:
<Md remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeSlug, rehypeAutolinkHeadings]}>
{markdown}
</Md>📂 Accessing MDAST + HAST
type astRef = {
current: { mdast: Root; hast: HastRoot }[];
};Useful for:
- 📄 DOCX export (
mdast2docx) - 🧪 AST testing or analysis
- 🛠️ Custom tree manipulation
📊 Performance
TL;DR:
@m2d/react-markdownperforms competitively withreact-markdown, especially on medium and large documents.
Benchmarks include:
- Multiple markdown fixture types (short, long, complex, deeply nested)
- Plugin configurations like
remark-gfm,remark-math,rehype-raw - Visual comparisons using interactive Mermaid
xychart-betacharts - Ops/sec, ±%, and future memory profiling
💬 Upcoming Changes – Seeking Feedback
We're proposing a major change to the internal astRef structure to better support MDX-style custom components and rendering flexibility:
Key goals:
- Allow
<Md>to embed child components like JSX/MDX - Simplify recursive rendering model
- Improve performance and reduce abstraction overhead
🧭 Roadmap
- [ ] 🔄 Merge JSX +
<Md>segments into unified AST - [x] 🧪 Structural test utilities
- [x] 🧑🏫 Next.js + DOCX example
🌍 Related Projects
mdast2docx– Convert MDAST →.docxunified– Syntax tree ecosystemreact-markdown– Popular alternative (less customizable)
🙏 Acknowledgements
We are deeply grateful to the open-source community whose work made this project possible.
- 🌱 react-markdown – For pioneering a React-based Markdown renderer. This library builds on its ideas while extending flexibility and SSR-readiness.
- 🛠 unified – The brilliant engine powering our markdown-to-AST transformations.
- ✨ remark and rehype – For their modular ecosystems that make parsing and rendering delightful.
- 🧾 mdast2docx – Our sister project that inspired the MDAST-first architecture of this library.
💖 To the maintainers, contributors, and communities behind these projects — thank you for your generosity, vision, and dedication to making the web better for everyone.
📘 License
Licensed under the MPL-2.0.
💡 Want to support this project? Sponsor or check out our courses!
