react-markdown

Safely render Markdown as React elements, no dangerouslySetInnerHTML required

Library
npm
v10.1.0
15,928 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
65 /100 Good
Development Activity 56
Maintenance 36
Community 68
Maturity 60
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
85 /100 Excellent
Architecture 82
Code Quality 85
Innovation 88
Learning Curve 85

react-markdown is a React component that turns a Markdown string into a tree of React elements instead of raw HTML, so nothing ever passes through dangerouslySetInnerHTML and the app stays safe from injected scripts by default. Under the hood it delegates parsing and transformation to the unified ecosystem (remark for Markdown, rehype for HTML), which means it inherits a mature plugin system, full CommonMark compliance, and optional GitHub Flavored Markdown support via remark-gfm.

Beyond safety, its main draw is customizability: any HTML tag produced by the render can be swapped for a React component via the components prop, letting consumers replace <a>, <img>, or <code> with app-specific implementations (routed links, lazy images, syntax-highlighted code blocks) without forking the renderer. Three entry points cover different rendering needs — a synchronous Markdown component for the common case, MarkdownAsync for server-side async plugins, and MarkdownHooks for client-side async plugins via React hooks.

What You Get

  • A drop-in <Markdown> component that renders a Markdown string prop straight to React elements
  • Automatic protection against script injection — HTML in the source markdown is stripped or escaped by default via a safe unified pipeline
  • A components prop to remap any rendered tag (headings, links, images, code blocks, tables) to your own React components
  • remarkPlugins and rehypePlugins arrays for hooking into the wider unified plugin ecosystem (GFM tables/strikethrough, footnotes, math, syntax highlighting, table of contents, and more)
  • MarkdownAsync and MarkdownHooks variants for rendering with async plugins on the server or client respectively
  • A configurable urlTransform hook (with a safe default) to sanitize or rewrite every URL-bearing attribute in the output

Common Use Cases

  • Rendering user-authored Markdown (comments, README previews, CMS content) safely in a React app without hand-rolling XSS sanitization
  • Building a docs or blog site where Markdown needs to render through the app’s own design-system components instead of raw HTML tags
  • Adding GitHub Flavored Markdown features (tables, task lists, strikethrough, autolinks) via remark-gfm on top of the base renderer
  • Rendering LLM chat responses that come back as Markdown, with custom components for code blocks, links, and citations

Under The Hood

Architecture — The package exports Markdown (sync), MarkdownAsync (async, server-safe), and MarkdownHooks (async via React hooks) from lib/index.js. Internally it builds a unified() processor chaining remarkParse → user remarkPlugins → remarkRehype (with allowDangerousHtml: true so raw HTML survives as a raw node instead of being silently dropped) → user rehypePlugins. createFile() wraps the Markdown string in a VFile. After processing, a post() step runs a single unist-util-visit pass over the resulting hast tree to: reject deprecated pre-v6 props with actionable errors (via devlop’s unreachable()), convert or strip raw HTML nodes depending on skipHtml, rewrite every URL-bearing attribute through urlTransform/defaultUrlTransform (a protocol-allowlist regex), and filter elements via allowedElements/disallowedElements/allowElement. Finally hast-util-to-jsx-runtime’s toJsxRuntime() turns the filtered hast tree into React elements using the automatic JSX runtime, passing the original hast node to matched custom components via passNode. MarkdownHooks wraps this same pipeline in useMemo/useEffect/useState with a cancellation guard, deferring async-plugin work to the client without blocking initial render.

Tech Stack — A single index.js re-export plus a ~450-line lib/index.js, authored as pure ESM ("type": "module") checked-JS-with-JSDoc rather than .ts source, with tsc emitting the shipped .d.ts. Runtime dependencies are entirely from the unified/remark/rehype ecosystem (unified, remark-parse, remark-rehype, hast-util-to-jsx-runtime, html-url-attributes, unist-util-visit, vfile, devlop), plus type-only @types/hast/@types/mdast. React is a peer dependency only (>=18), never bundled. Dev tooling is Node’s built-in test runner (not Jest/Vitest), xo/prettier for lint and format, c8 for coverage, and type-coverage for strict type enforcement.

Code Quality — test.jsx is a single 1,280-line, 87-case suite covering the three exported components, deprecated-prop error paths, element allow/deny-listing, custom components, plugin composition, URL transforms, and SSR streaming, run via node:test with global-jsdom and @testing-library/react. The test script gates on c8 --100 (100% statement coverage) and type-coverage --at-least 100 --strict. Naming is terse and consistent (createProcessor/createFile/post), and error handling favors explicit, descriptive unreachable() throws that point at a changelog anchor for every removed/renamed legacy option rather than failing silently.

API Design — The public surface is deliberately small: a default Markdown export plus two async variants, so the common case is <Markdown>{md}</Markdown> with zero required configuration. Extensibility layers on cleanly via remarkPlugins/rehypePlugins arrays (the same plugin objects used across the broader unified ecosystem) and a components map that mirrors JSX.IntrinsicElements, so anyone familiar with remark/rehype faces almost no new API surface. Deprecated pre-v6 props throw actionable errors instead of silently misbehaving — unusually good DX for a library with a long breaking-change history. The readme is extensive, with runnable examples for plugins, custom components, and math/syntax-highlighting integrations.

Used by 165 apps in this directory

Go
75%
AGPL 3.0

Coder

Code Editors · Developer Tools · Devops

17,157

Self-hosted cloud development environments and AI coding agents — defined in Terraform, connected via WireGuard, automatically shut down when idle.

View details
91
Repo Health
90
Technical
66
Dependency
Built with
Go 75%
TypeScript 23%
Updated 6 days ago
JavaScript
90%
Other

CodeSandbox

Code Editors · Developer Tools

13,652

Instantly ready browser-based IDE that runs full npm dependency resolution and transpilation entirely client-side, with no server needed.

View details
67
Repo Health
76
Technical
63
Dependency
Built with
JavaScript 90%
Updated 1 weeks ago
TypeScript
84%
Apache 2.0

Continue

AI Code Assistants · AI Development · Automation

36,303

Open-source coding agent for VS Code, JetBrains, and CLI with support for 30+ LLM providers.

View details
66
Repo Health
88
Technical
62
Dependency
Built with
TypeScript 84%
Updated 1 weeks ago
TypeScript
45%
Other

Convex Backend

Databases · Developer Tools

12,754

Open-source reactive database that lets developers build live-updating apps with pure TypeScript, strong consistency, and real-time subscriptions—no separate API layer required.

View details
88
Repo Health
82
Technical
65
Dependency
Built with
TypeScript 45%
Rust 43%
Updated 6 days ago
Rust
67%
Other

DefGuard

Authentication · Networking · Security

2,882

Self-hosted secure remote access that unifies WireGuard VPN, identity management, and connection-level MFA in one open-source platform.

View details
86
Repo Health
82
Technical
71
Dependency
Built with
Rust 67%
TypeScript 30%
Updated 1 weeks ago
TypeScript
97%
MIT

DenchClaw

AI Agents · CRM

1,660

An AI-native CRM you self-host on your own machine, built on the OpenClaw agent framework, with a DuckDB backend and pre-built agent skills for managing contacts, deals, reports, and 500+ outreach integrations from natural-language chat.

View details
47
Repo Health
73
Technical
71
Dependency
Built with
TypeScript 97%
Updated 4 months ago
TypeScript
98%
Other

Dokploy

Devops · Hosting Control Panel · Security

37,989

Self-hosted PaaS that deploys apps and databases on your own VPS using Docker, Traefik, and multi-build-system orchestration

View details
89
Repo Health
76
Technical
64
Dependency
Built with
TypeScript 98%
Updated 6 days ago
TypeScript
100%
Other

Dub

Analytics · Marketing

24,935

The open-source link attribution platform for short links, conversion tracking, and affiliate programs — powering 100M+ clicks monthly.

View details
81
Repo Health
78
Technical
62
Dependency
Built with
TypeScript 100%
Updated 6 days ago
TypeScript
96%
Other

Dyad

AI Assistants · AI Code Assistants · AI Development

22,046

Build AI-powered apps locally with your own keys, your own models, and zero cloud lock-in.

View details
87
Repo Health
83
Technical
69
Dependency
Built with
TypeScript 96%
Updated 1 weeks ago

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers