rehype-react

A unified/rehype plugin that compiles HTML syntax trees into React, Preact, Solid, or Vue JSX elements.

Library
npm
v8.0.0
438stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
39/100Needs Attention
Development Activity0
Maintenance20
Community56
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
74/100Good
Architecture78
Code Quality92
Innovation80
Learning Curve45

rehype-react is a plugin for the unified/rehype ecosystem that registers a compiler turning a hast (HTML abstract syntax tree) into JSX elements instead of a serialized HTML string. Rather than producing markup you then have to re-parse or inject with dangerouslySetInnerHTML, it hands back real React (or Preact, Solid, Vue) elements from unified().process(), so content that started life as markdown or raw HTML can be rendered directly inside a JSX tree with full control over individual node output.

It is deliberately small in scope: a single default export that plugs into an existing unified pipeline (typically after rehype-parse or remark-rehype) and delegates the actual hast-to-JSX conversion to hast-util-to-jsx-runtime. Framework differences in attribute and style-property casing are handled through simple options, and a components map lets callers swap in custom React components for specific HTML tags — useful for design systems, sanitization-aware rendering, or intercepting elements like <img> and <a> for custom behavior.

What You Get

  • A unified().use(rehypeReact, options) compiler that returns JSX elements from file.result instead of a string
  • Per-framework casing options (elementAttributeNameCase, stylePropertyNameCase) so the same plugin works across React, Preact, Solid, and Vue
  • A components option to override rendering of specific hast element names with custom React components
  • A passNode option to expose the original hast node to custom components for advanced use cases
  • Full TypeScript types (Components, Options) re-exported from hast-util-to-jsx-runtime
  • Automatic conversion of obsolete align attributes on table cells into CSS style props

Common Use Cases

  • Rendering markdown content as live React elements inside a Next.js or other React app via remark-rehype + rehype-react
  • Building custom markdown/MDX-like renderers that need fine-grained control over which HTML tags map to which React components
  • Swapping specific elements (headings, links, images) for design-system components while keeping the rest of the tree as plain HTML tags
  • Targeting non-React JSX runtimes (Preact, Solid, Vue) from the same rehype pipeline by changing only the JSX runtime options

Under The Hood

Architecture The package is a thin adapter over the unified plugin architecture: its default export is called with this bound to the active Processor, and it attaches a compiler function to self.compiler following unified’s plugin-attachment convention. That compiler receives the final hast Root and delegates entirely to hast-util-to-jsx-runtime’s toJsxRuntime, passing through the file path and caller-supplied options. There is effectively no independent business logic in this repository — the architecture is a deliberate, narrow seam between rehype’s tree-processing pipeline and a JSX runtime, which keeps the surface area (and the risk of it breaking on ecosystem changes) very small.

Tech Stack It’s a Node.js 16+, ESM-only package ("type": "module", "exports": "./index.js") with zero runtime framework dependency beyond unified (^11) and hast-util-to-jsx-runtime (^2), plus @types/hast for typings. Types are authored as JSDoc comments and checked with plain tsc in checkJs/strict mode, with declaration files emitted separately via tsc --build; type-coverage enforces 100% strict type coverage as part of the build. Linting runs through xo (an opinionated ESLint preset) and formatting through prettier, both wired into a single npm run format script alongside remark-cli for linting the README itself.

Code Quality Tests live in a single test.js using Node’s built-in node:test and node:assert/strict, building hast trees with hastscript and asserting against both React.createElement output and server-rendered markup via react-dom/server. Coverage is enforced at 100% through c8 --100, and CI (GitHub Actions, main.yml plus a bb.yml bundle-size check) runs the full build/format/test-coverage chain. Error handling is minimal by design — a single explicit throw when required Fragment/jsx/jsxs options are missing — with everything else deferred to the well-tested hast-util-to-jsx-runtime dependency.

API Design The public API is a single default export used via .use(rehypeReact, options), which keeps the surface area small and consistent with other unified/rehype plugins developers likely already know. The framework-casing table in the README (React vs. Preact vs. Solid vs. Vue) makes cross-framework usage explicit rather than implicit, and the components/passNode options give escape hatches for advanced rendering without complicating the default path. The main ergonomic cost is that callers must explicitly import and pass their JSX runtime (react/jsx-runtime or react/jsx-dev-runtime) themselves, which is a small but real piece of boilerplate compared to frameworks that infer this automatically.

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

Search