Compatibility
This renderer isn't a drop-in replacement for react-markdown. It's a
different package, but the props people usually migrate have the same names,
the same meanings and the same default URL policy. Where the behaviour does
differ, it's listed below.
The numbers below come from a test that renders identical input through both
packages and compares normalized HTML. It regenerates
docs/COMPATIBILITY.md
on every run, so treat that file as the source of truth. This page summarizes it.
Result#
Measured against react-markdown@10.1.0. 39 comparisons across 11 props, and
39 produce identical markup.
| Status | Count |
|---|---|
| Compatible | 11 |
| Intentionally different | 1 |
| Not supported yet | 1 |
| Compatible with a documented change | 1 |
The 11 compatible props#
| Prop | What was compared |
|---|---|
children | Headings, emphasis, lists, code, quotes, links, hard breaks, empty string |
components | Element-name keys map to components, and the same props arrive |
remarkPlugins | Tree transforms and dialect plugins, including remark-gfm |
rehypePlugins | hast plugins running after mdast to hast and before the content policy |
remarkRehypeOptions | Footnote label, back-label and clobber prefix |
allowedElements | Only listed tags survive, and children of a removed element go with it |
disallowedElements | Listed tags are removed and everything else stays |
allowElement | The predicate receives element, index and parent |
unwrapDisallowed | A removed element is replaced by its children |
urlTransform | Runs on every URL attribute, with the same default algorithm |
skipHtml | Same meaning and the same false default |
Both packages default skipHtml to false, so raw HTML renders as visible
escaped text. Neither executes raw HTML without an explicit rehype-raw opt-in.
The rows that differ#
className is intentionally different#
react-markdown 10 throws on a className prop. This renderer has no
className prop either, and TypeScript rejects it, but at runtime it is
ignored rather than thrown.
So JavaScript code that still passes className will quietly lose the wrapper
instead of throwing. Use components or the opt-in classNames hooks
described in styling instead.
MarkdownAsync and MarkdownHooks are not supported yet#
react-markdown 10 exports both for plugins that need async work. This
renderer is synchronous only, so there's no equivalent export and an async
remark or rehype plugin won't run.
remarkPlugins on a precompiled document has a documented change#
react-markdown only ever takes a string, so every plugin runs at parse time.
This renderer also accepts an already-compiled MarkdownDocument.
A plugin that changes the dialect, such as remark-gfm, can't apply to text
that was already parsed. Plugins that transform the tree still run. You'll want
to compile with the same extensions you render with, or just pass the string.
// The plugin cannot add table syntax to text that is already a tree.
const document = compileMarkdown(source, { preset: gfmPreset })
<Markdown document={document} />What is not covered#
Anything outside the prop surface doesn't have a react-markdown equivalent,
so it isn't really a compatibility question. That includes bundle size, the
MarkdownDocument input, presets, extensions, the editor and the variables
plugin.
Migrating#
The migration guide walks through the codemod and the manual steps. Since the claims on this page are generated from tests, I'd check the matrix for your pinned version before planning a migration.
Last updated on