UNPKG

mdx-render

Version:

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.

243 lines (166 loc) โ€ข 7.92 kB
# MDX Renderer [`@m2d/react-markdown`] <img src="https://raw.githubusercontent.com/mayank1513/mayank1513/main/popper.png" style="height: 40px"/> [![test](https://github.com/md2docx/react-markdown/actions/workflows/test.yml/badge.svg)](https://github.com/md2docx/react-markdown/actions/workflows/test.yml) [![Maintainability](https://api.codeclimate.com/v1/badges/aa896ec14c570f3bb274/maintainability)](https://codeclimate.com/github/md2docx/react-markdown/maintainability) [![codecov](https://codecov.io/gh/md2docx/react-markdown/graph/badge.svg)](https://codecov.io/gh/md2docx/react-markdown) [![Version](https://img.shields.io/npm/v/@m2d/react-markdown.svg?colorB=green)](https://www.npmjs.com/package/@m2d/react-markdown) [![Downloads](https://img.jsdelivr.com/img.shields.io/npm/d18m/@m2d/react-markdown.svg)](https://www.npmjs.com/package/@m2d/react-markdown) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/@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`](https://github.com/md2docx/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 ```bash pnpm add @m2d/react-markdown ``` **_or_** ```bash npm install @m2d/react-markdown ``` **_or_** ```bash yarn add @m2d/react-markdown ``` --- ## ๐Ÿš€ Server vs Client By default, this package is SSR-safe and has **no client-specific hooks**. ### โœ… Server (default): ```tsx import { Md } from "@m2d/react-markdown"; ``` ### ๐Ÿ” Client (for dynamic reactivity/memoization): ```tsx import { Md } from "@m2d/react-markdown/client"; ``` This version supports client-side behavior with memoization and dynamic JSX rendering. --- ## โšก Example: Rendering + Exporting DOCX ```tsx 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**: ```tsx 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 ```tsx 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: ```tsx <Md remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeSlug, rehypeAutolinkHeadings]}> {markdown} </Md> ``` --- ## ๐Ÿ“‚ Accessing MDAST + HAST ```ts 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 โ†’](./benchmark.md) 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 โ†’](https://github.com/md2docx/react-markdown/discussions/3) 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`](https://github.com/md2docx/mdast2docx) โ€“ Convert MDAST โ†’ `.docx` - [`unified`](https://unifiedjs.com/) โ€“ Syntax tree ecosystem - [`react-markdown`](https://github.com/remarkjs/react-markdown) โ€“ Popular alternative (less customizable) --- ## ๐Ÿ™ Acknowledgements We are deeply grateful to the open-source community whose work made this project possible. - ๐ŸŒฑ **[react-markdown](https://github.com/remarkjs/react-markdown)** โ€“ For pioneering a React-based Markdown renderer. This library builds on its ideas while extending flexibility and SSR-readiness. - ๐Ÿ›  **[unified](https://github.com/unifiedjs/unified)** โ€“ The brilliant engine powering our markdown-to-AST transformations. - โœจ **[remark](https://github.com/remarkjs/remark)** and **[rehype](https://github.com/rehypejs/rehype)** โ€“ For their modular ecosystems that make parsing and rendering delightful. - ๐Ÿงพ **[mdast2docx](https://github.com/md2docx/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](https://www.mozilla.org/en-US/MPL/2.0/). > ๐Ÿ’ก Want to support this project? [Sponsor](https://github.com/sponsors/mayank1513) or check out our [courses](https://mayank-chaudhari.vercel.app/courses)! --- <p align="center" style="text-align:center">Built with โค๏ธ by <a href="https://mayank-chaudhari.vercel.app" target="_blank">Mayank Kumar Chaudhari</a></p>