markdown-to-jsx@9.10.0
Minor Changes
- 02bae9f: Heading ids are generated from each heading's plain text content instead of its raw markdown source. Link destinations, formatting markers, and image alt text no longer leak into the id (for example
## [text](https://e.com)becomesid="text"rather thanid="texthttpsecom"). Anchors on headings that contained links, images, or autolinks may change; plain-text headings are unaffected. Duplicate-id suffixes (foo,foo-1) still apply. - 02bae9f: Rejected image destinations now use
nullon the parsed AST the same way rejected links already do, so TypeScript consumers can treatImageNode.targetandLinkNode.targetasstring | null. Compilers still omitsrcfor rejected images and the markdown compiler still re-emits them as![alt](). - 4d08fd8: Headings that share the same text now get unique HTML ids automatically (
introduction,introduction-1,introduction-2), matching the usual Markdown hosting behavior. A customslugifystill controls the base string; uniqueness is applied afterward, so you no longer need a stateful slugify closure that breaks under React Strict Mode.
Patch Changes
-
02bae9f: Link and image destinations that hide a dangerous scheme behind HTML entities (for example
[x](javascript:alert(1))) are now rejected the same way as a literaljavascript:URL. Compilers drop the href for rejected links and omit the src for rejected images. The markdown compiler re-emits a rejected image as![alt]()rather than. Direct AST rendering also re-checks link targets before they become hrefs. -
02bae9f: Single-line
<script>,<style>,<pre>, and<textarea>blocks keep their text content whentagfilteris off, including underforceInline. Previously the React output could emit an empty tag and drop the body. -
4d08fd8: Custom JSX components written in PascalCase, and hyphenated custom elements, keep their markdown children when a blank line appears between the opening and closing tags. Content after the blank no longer leaks out as a sibling of the component.
-
e9a253d: Ship an
llms.txtcheatsheet with the package and at markdown-to-jsx.quantizor.dev/llms.txt, so coding assistants can pick up the entry points, options, recipes, and AST shapes in a single short read instead of the full README.The cheatsheet leads with the questions people actually ask: why a single newline is not a line break, how to wire up a syntax highlighter or KaTeX, opening links in a new tab, restricting which tags render, and the traps around indented template literals and case-sensitive override keys.
Two documentation corrections come along with it. The HTML entry point example named an export that does not exist; the helper there is
astToHTML. And the class added to a fenced code block islanguage-<lang>, with the olderlang-<lang>alongside it on the JSX renderers, rather thanlang-<lang>alone as previously written. -
02bae9f: The markdown compiler now re-emits processing instructions (
<?xml ?>), CDATA sections, declarations (<!DOCTYPE html>), and orphan closing tags exactly as written. Previously these were reconstructed as a generic self-closing element, which mangled a processing instruction like<?xml version="1.0"?>down to<? />and dropped CDATA and declaration content entirely. -
02bae9f:
optimizeForStreamingnow defers incomplete HTML the same way in every compiler, including Solid and Vue. Tag-like prefixes that have not finished arriving (Hello <Citation,<!--…) stay hidden until they complete, while ordinary less-than text (5 < 3) keeps rendering. -
02bae9f: Dangerous
url(javascript:…)(and similar) payloads in raw HTMLstyleattributes are now stripped from the HTML and Markdown string outputs, matching the React-family compilers. -
02bae9f: Table cells that contain a backslash before a pipe are escaped correctly when compiling back to Markdown, so the pipe no longer splits the row on re-parse.
-
02bae9f: Dangerous HTML tags (
<script>,<iframe>,<style>, and similar) are escaped by default across the React, HTML, Solid, Vue, and React Native outputs. Matching GFM, only each tag's leading<is neutralized; the body and closing tag stay visible as inert text instead of being dropped. Solid, Vue, and React Native previously rendered these tags live unlesstagfilter: truewas passed explicitly, and escaped output in every renderer stopped at the opener. Direct calls toastToJSXfollow the same default.