Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

957 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

MDX Renderer [@m2d/react-markdown]

test Maintainability codecov Version Downloads npm bundle size

✨ 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-markdown

or

npm install @m2d/react-markdown

or

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.current is 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 children
  • Omit – removes element and content entirely
  • CodeBlock - 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-markdown performs competitively with react-markdown, especially on medium and large documents.

πŸ‘‰ See full benchmarks β†’

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-beta charts
  • 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:

πŸ‘‰ Join the discussion β†’

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
  • πŸ§ͺ Structural test utilities
  • πŸ§‘β€πŸ« Next.js + DOCX example

🌍 Related Projects


πŸ™ 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!


Built with ❀️ by Mayank Kumar Chaudhari

About

SSR-ready React Markdown renderer with MDAST reuse, JSX support, and unified plugin pipeline.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages