npm / markdown-to-jsx
markdown-to-jsx
What changed in markdown-to-jsx 9, from its official release notes, upgrade guides and advisories. Sources checked 2026-10-21.
8 breaking1 security9 new APIs and options6 performance4 behavior and defaults40 fixes and other
See which of these apply to your code, ranked, in your agent:
npx @unstale/cli initmarkdown-to-jsx 968 changes
Breaking changes 8
Dangerous tags are escaped by default across React, HTML, Solid, Vue, and React Native outputs; their bodies and closing tags remain visible as inert text.
Heading ids are generated from plain text rather than raw Markdown, so links, formatting markers, and image alt text no longer affect anchors.
Destinations that conceal dangerous schemes with HTML entities are rejected; compilers omit unsafe href or src values, and direct AST rendering re-checks link targets.
Dangerous url(javascript:…) and similar payloads are stripped from HTML and Markdown string outputs.
Dangerous event-handler and URL attributes, srcdoc, and obfuscated unsafe schemes are stripped before output; safe attributes and data:image URLs remain supported.
A reference definition split across blockquote lines is no longer matched by a link using the raw, unnormalized label.
Each React Native styles key is narrowed to the style type accepted by its component, catching mismatched styles at compile time.
HTML block content on its own line without surrounding blank lines is preserved as literal text; content surrounded by blank lines continues to parse markdown.
Security 1
Markdown with long runs of brackets or footnote markers now parses in linear time, avoiding severe slowdowns when rendering untrusted input on a server.
New APIs and options 9
React Native elements can be replaced with custom components via overrides.
Adds a style key for the checkmark glyph of a GFM task item.
Adds styles.footnote to style React Native footnote references, which now render as superscript.
Adds a style key for the checked-box accent of a GFM task item.
Adds a style key for table cell grid lines.
Adds a style key for the bold table header run.
Adds a style key for table row grid lines.
styles.text sets a base font and color for all text at once.
Adds an option to skip frontmatter detection entirely.
Performance 6
With the option enabled, incomplete-syntax suppression scans only the block that can hold the live edge, reducing repeated work on deeply nested content.
Compiling a large document runs roughly 5–7% quicker, especially for list- and heading-heavy content.
Documents with many bold or italic spans now parse much faster, avoiding sharp slowdowns on very large or adversarial inputs.
The component no longer re-parses unchanged content when a parent re-renders with unchanged props.
Parsing is around 40% faster on large documents, with the biggest gains on link-heavy and code-heavy content.
Markdown with many malformed link starts parses quickly instead of slowing to a crawl on large inputs.
Behavior and default changes 4
The option now works in the React Native renderer, suppressing partial structures during streaming.
React Native output now has readable defaults for headings, code, block spacing, blockquotes, tables, and GFM task items; styles remain customizable.
The component accepts
string[]children to support the common JSX case where children arrive as a coalesced array.Task list items now use row and center-aligned defaults so checkboxes and labels sit on the same line; set
styles.listItemto opt out.
Fixes and other changes 40
HTML tag overrides are applied regardless of the casing of the source tag.
Shortcut reference links labeled
__proto__orconstructorno longer throw and resolve like any other reference label.Link destinations preserve punctuation such as underscores while markdown is streamed, preventing generated links from being changed or broken.
Browser bundles no longer crash when reading environment checks because the library no longer imports Node's process module.
PascalCase custom JSX components and hyphenated custom elements retain Markdown children across a blank line, which no longer leaks following content as a sibling.
Headings with identical text receive unique HTML ids; custom slugify still sets the base string, with uniqueness applied afterward.
Rejected image destinations use null in the parsed AST, allowing TypeScript consumers to treat ImageNode.target as string | null.
TypeScript consumers can treat LinkNode.target as string | null, matching rejected link destinations on the parsed AST.
Processing instructions, CDATA sections, declarations, and orphan closing tags are re-emitted exactly as written instead of being reconstructed as generic self-closing elements.
Incomplete HTML is deferred consistently across compilers, including Solid and Vue, while ordinary less-than text continues rendering.
Backslashes before pipes in table cells are escaped when compiling to Markdown, preventing the pipe from splitting the row when reparsed.
Single-line script, style, pre, and textarea blocks preserve their text content when tagfilter is off, including under forceInline.
The last paragraph inside a blockquote no longer leaves extra space below it.
Compiled Markdown better round-trips to the same document, preserving literal characters, table and list structure, code delimiters, titles, raw HTML attributes, and empty inline elements.
Tables remain hidden until enough syntax has streamed to render them, then stay visible as rows arrive, across every renderer.
Footnote references render as superscript instead of bold, and notes in the list appear on one line next to their numbers.
Fixes React key warnings when raw HTML mixes with other content or a custom component follows a heading.
Prevents crashes when text, block elements, or images are mixed; image links remain tappable.
Vue renderRule types now allow a custom rule and its next callback to return arrays of nodes.
URLs containing emoji and other non-BMP Unicode characters render without crashing.
Text on its own line after a nested HTML element now renders when no blank line separates them, consistently across React, React Native, Solid, and Vue outputs.
Fast-skip no longer truncates bare email local-parts containing inline-special characters.
React Native overrides now fire for parsed markdown elements, including inline emphasis, fenced code, headings, lists, and GFM task checkboxes.
Lists, blockquotes, fenced code, and headings inside table cells now render as nested content without breaking surrounding rows or dropping closing tags.
Fixes the Vue adapter warning about a non-function default slot when component overrides are used.
The HTML compiler now preserves closing tags for empty non-void elements.
Frontmatter detection no longer consumes content when a thematic break starts the document; detection now validates YAML key-value syntax.
Markdown lists inside HTML table cells now render as proper nested lists instead of breaking the table structure.
Adds key props to thead and tbody in table rendering to resolve a React key warning.
Void HTML elements no longer drop subsequent content when they are not followed by a newline.
Fixes streaming mode incorrectly stripping self-closing custom component tags and leaking incomplete trailing tags as escaped text in inline content.
Fixes missing TypeScript declaration files in the published package so consumers can use its types.
Tables with only a header row and no data rows no longer render an empty tbody.
Fixes the development warning “Attempted to render without development properties” in React 19 RSC.
Trailing asterisks are trimmed from bare URLs wrapped in bold Markdown so generated link hrefs are correct.
Emphasis delimiters closing before hard line breaks are now resolved correctly.
Raw React elements now unconditionally include
_storeso React dev-mode validation works across bundler environments.Fixed broken exports in bundled output caused by a Bun bundler bug with cross-entry re-exports.
Nested HTML blocks with the same tag name now correctly match depth-paired closing tags.
Ambiguous Setext headings are suppressed during streaming to avoid premature heading rendering.