This renderer is not a drop-in replacement for react-markdown. It is a
different package with a compatible surface for the props people actually
migrate: same prop names, same meanings, and the same default URL policy.
Where behaviour differs, the difference is listed below rather than smoothed
over.
Measured against react-markdown@10.1.0 by rendering identical input through
both packages and comparing normalized HTML. 39 comparisons across
11 props; 39 produce identical markup.
| Prop | Status | Cases matching | Evidence |
|---|---|---|---|
children |
compatible | 4/4 | tests/compatibility.test.tsx › children |
components |
compatible | 4/4 | tests/compatibility.test.tsx › components |
remarkPlugins |
compatible | 4/4 | tests/compatibility.test.tsx › remarkPlugins |
rehypePlugins |
compatible | 3/3 | tests/compatibility.test.tsx › rehypePlugins |
remarkRehypeOptions |
compatible | 3/3 | tests/compatibility.test.tsx › remarkRehypeOptions |
allowedElements |
compatible | 4/4 | tests/compatibility.test.tsx › allowedElements |
disallowedElements |
compatible | 3/3 | tests/compatibility.test.tsx › disallowedElements |
allowElement |
compatible | 3/3 | tests/compatibility.test.tsx › allowElement |
unwrapDisallowed |
compatible | 3/3 | tests/compatibility.test.tsx › unwrapDisallowed |
urlTransform |
compatible | 4/4 | tests/compatibility.test.tsx › urlTransform |
skipHtml |
compatible | 4/4 | tests/compatibility.test.tsx › skipHtml |
className |
intentionally different | — | tests/compatibility.test.tsx › beyond the prop surface (react-markdown throws / this renderer ignores) |
MarkdownAsync, MarkdownHooks |
not supported yet | — | tests/compatibility.test.tsx › beyond the prop surface (exports are absent from @react-markdown-kit/renderer) |
remarkPlugins on a precompiled document |
compatible with documented change | — | tests/compatibility.test.tsx › beyond the prop surface (remark-gfm produces a table from a string but not from a document compiled without it) |
- compatible: 11
- intentionally different: 1
- not supported yet: 1
- compatible with documented change: 1
A Markdown string as children renders the same tree.
Inputs compared:
- identical — headings and emphasis
- identical — lists, code and quotes
- identical — links, reference links and hard breaks
- identical — empty string
Element-name keys map to React components; the same props arrive.
Inputs compared:
- identical — heading override
- identical — anchor override receives href
- identical — paragraph override
- identical — several overrides at once
Both tree-transforming plugins and dialect plugins (remark-gfm) behave the same.
Inputs compared:
- identical — remark-gfm tables
- identical — remark-gfm task list and strikethrough
- identical — remark-gfm autolinks and footnotes
- identical — custom mdast transform
hast plugins run after mdast->hast and before the content policy.
Inputs compared:
- identical — attribute stamping
- identical — class injection
- identical — plugin plus components
Options reach remark-rehype, including footnote labels and clobber prefixes.
Inputs compared:
- identical — footnote label
- identical — clobber prefix
- identical — footnote back-label
Only the listed tag names survive; children of a removed element go with it.
Inputs compared:
- identical — paragraphs only
- identical — headings and text
- identical — nothing allowed
- identical — inline allowed inside removed block
The listed tag names are removed, everything else stays.
Inputs compared:
- identical — drop headings
- identical — drop emphasis
- identical — drop lists
The predicate receives (element, index, parent) and removing is the same decision.
Inputs compared:
- identical — reject by tag name
- identical — reject by index
- identical — reject by parent tag
A removed element is replaced by its children rather than dropped.
Inputs compared:
- identical — unwrap emphasis
- identical — unwrap heading
- identical — unwrap via allowElement
Runs on every URL attribute; returning an empty string blanks it. The default algorithm is the same one react-markdown ships.
Inputs compared:
- identical — rewrite href
- identical — blank everything
- identical — default blocks javascript:
- identical — default keeps mailto:
Same meaning and the same default. Both packages default to false, rendering raw HTML as visible escaped text rather than executing it; skipHtml: true removes it in both. An earlier revision of this renderer defaulted to true, which was the only behavioural difference on this prop and amounted to silently dropping content the author wrote. Neither package executes raw HTML without an explicit rehype-raw opt-in.
Inputs compared:
- identical — default (unset)
- identical — skipHtml true
- identical — skipHtml false
- identical — dangerous html, default
react-markdown 10 throws Unexpected className prop, remove it. This renderer has no className prop either, but ignores it at runtime rather than throwing; TypeScript rejects it. Use components or the opt-in classNames hooks. Migrating JavaScript code that still passes className will lose the wrapper silently instead of failing loudly.
Evidence: react-markdown throws / this renderer ignores.
react-markdown 10 exports MarkdownAsync and MarkdownHooks for plugins that need async work. This renderer is synchronous only; there is no equivalent export, and an async remark/rehype plugin will not work.
Evidence: exports are absent from @react-markdown-kit/renderer.
react-markdown only ever takes a string, so every plugin runs at parse time. This renderer also accepts an already-compiled MarkdownDocument, and a plugin that changes the dialect (remark-gfm and anything else registering micromark extensions) cannot apply to text that has already been parsed. Tree-transforming plugins still run. Compile with the same extensions you render with, or pass the string.
Evidence: remark-gfm produces a table from a string but not from a document compiled without it.
Everything outside the prop surface — bundle size, the MarkdownDocument
input, presets, extensions, the editor and variables packages — has no
react-markdown equivalent and is not a compatibility question.