[![npm version](https://badge.fury.io/js/markdown-to-jsx.svg)](https://badge.fury.io/js/markdown-to-jsx) [![downloads](https://badgen.net/npm/dy/markdown-to-jsx)](https://npm-stat.com/charts.html?package=markdown-to-jsx) `markdown-to-jsx` is a gfm+commonmark compliant markdown parser and compiler toolchain for JavaScript and TypeScript-based projects. It is extremely fast, capable of processing large documents fast enough for real-time interactivity. Some special features of the library: - Arbitrary HTML is supported and parsed into the appropriate JSX representation without `dangerouslySetInnerHTML` - Any HTML tags rendered by the compiler and/or `` component can be overridden to include additional props or even a different HTML representation entirely. - All GFM special syntaxes are supported, including tables, task lists, strikethrough, autolinks, tag filtering, and more. - Fenced code blocks with [highlight.js](https://highlightjs.org/) support; see [Syntax highlighting](#syntax-highlighting) for instructions on setting up highlight.js.

Table of Contents

- [Upgrading](#upgrading) - [From v8.x to v9.x](#from-v8x-to-v9x) - [From v7.x to v8.x](#from-v7x-to-v8x) - [Installation](#installation) - [Usage](#usage) - [Entry Points](#entry-points) - [Main](#main) - [React](#react) - [React Server Components RSC](#react-server-components-rsc) - [React Native](#react-native) - [SolidJS](#solidjs) - [Vue.js](#vuejs) - [HTML](#html) - [Markdown](#markdown) - [Library Options](#library-options) - [All Options](#all-options) - [options.createElement](#optionscreateelement) - [options.forceWrapper](#optionsforcewrapper) - [options.overrides](#optionsoverrides) - [options.evalUnserializableExpressions](#optionsevalunserializableexpressions) - [options.renderRule](#optionsrenderrule) - [options.sanitizer](#optionssanitizer) - [options.slugify](#optionsslugify) - [options.wrapper](#optionswrapper) - [Other useful recipes](#other-useful-recipes) - [options.wrapperProps](#optionswrapperprops) - [Syntax highlighting](#syntax-highlighting) - [Handling shortcodes](#handling-shortcodes) - [Usage with Preact](#usage-with-preact) - [AST Anatomy](#ast-anatomy) - [Node Types](#node-types) - [Example AST Structure](#example-ast-structure) - [Type Checking](#type-checking) - [Gotchas](#gotchas) - [Changelog](#changelog) - [Donate](#donate) ## Upgrading ### From v8.x to v9.x **Breaking Changes:** - **`ast` option removed**: The `ast: true` option on `compiler()` has been removed. Use the new `parser()` function instead to access the AST directly. ```typescript /** v8 */ compiler('# Hello world', { ast: true }) /** v9 */ parser('# Hello world') ``` - **`namedCodesToUnicode` option removed**: The `namedCodesToUnicode` option has been removed. All named HTML entities are now supported by default via the full entity list, so custom entity mappings are no longer needed. ```typescript /** v8 */ compiler('≤ symbol', { namedCodesToUnicode: { le: '\u2264' } }) /** v9 */ compiler('≤ symbol') ``` - **`tagfilter` enabled by default**: Dangerous HTML tags (`script`, `iframe`, `style`, `title`, `textarea`, `xmp`, `noembed`, `noframes`, `plaintext`) are now escaped by default in both HTML string output and React JSX output. Previously these tags were rendered as JSX elements in React output. ```typescript /** v8 */ tags rendered as JSX elements /** v9 */ tags escaped by default compiler('') // <script> /** Restore old behavior */ compiler('', { tagfilter: false }) ``` **New Features:** - **New `parser` function**: Provides direct access to the parsed AST without rendering. This is the recommended way to get AST nodes. - **New entry points**: React-specific, HTML-specific, and markdown-specific entry points are now available for better tree-shaking and separation of concerns. ```typescript // React-specific usage import Markdown, { compiler, parser } from 'markdown-to-jsx/react' // HTML string output import { compiler, astToHTML, parser } from 'markdown-to-jsx/html' // Markdown string output (round-trip compilation) import { compiler, astToMarkdown, parser } from 'markdown-to-jsx/markdown' ``` **Migration Guide:** 1. **Replace `compiler(..., { ast: true })` with `parser()`**: ```typescript /** v8 */ compiler(markdown, { ast: true }) /** v9 */ parser(markdown) ``` 2. **Migrate React imports to `/react` entry point** (optional but recommended): ```typescript /** Legacy */ import from 'markdown-to-jsx' /** Recommended */ import from 'markdown-to-jsx/react' ``` 3. **Remove `namedCodesToUnicode` option**: All named HTML entities are now supported automatically, so you can remove any custom entity mappings. ```typescript /** v8 */ compiler('≤ symbol', { namedCodesToUnicode: { le: '\u2264' } }) /** v9 */ compiler('≤ symbol') ``` **Note:** The main entry point (`markdown-to-jsx`) continues to work for backward compatibility, but React code there is deprecated and will be removed in a future major release. Consider migrating to `markdown-to-jsx/react` for React-specific usage.
### Older Migration Guides ### From v7.x to v8.x **Breaking Changes:** - Type `ParserResult` renamed to `ASTNode` - If you were using `MarkdownToJSX.ParserResult` in your code, update to `MarkdownToJSX.ASTNode` ```typescript /** v7 */ MarkdownToJSX.ParserResult[] /** v8+ */ MarkdownToJSX.ASTNode[] ``` - Multiple `RuleType` enums consolidated into `RuleType.textFormatted` - If you were checking for `RuleType.textBolded`, `RuleType.textEmphasized`, `RuleType.textMarked`, or `RuleType.textStrikethroughed`, update to check for `RuleType.textFormatted` and inspect the node's boolean flags: ```typescript /** v7 */ RuleType.textBolded /** v8+ */ RuleType.textFormatted && node.bold ```
## Installation Install `markdown-to-jsx` with your favorite package manager. ```shell npm i markdown-to-jsx ``` ## Usage `markdown-to-jsx` exports a React component by default for easy JSX composition: ES6-style usage\*: ```tsx import Markdown from 'markdown-to-jsx' import React from 'react' import { render } from 'react-dom' render(# Hello world!, document.body) /* renders:

Hello world!

*/ ``` \* **NOTE: JSX does not natively preserve newlines in multiline text. In general, writing markdown directly in JSX is discouraged and it's a better idea to keep your content in separate .md files and require them, perhaps using webpack's [raw-loader](https://github.com/webpack-contrib/raw-loader).** ### Entry Points `markdown-to-jsx` provides multiple entry points for different use cases: #### Main The legacy default entry point exports everything, including the React compiler and component: ```tsx import Markdown, { compiler, parser } from 'markdown-to-jsx' ``` _The React code in this entry point is deprecated and will be removed in a future major release, migrate to `markdown-to-jsx/react`._ #### React For React-specific usage, import from the `/react` entry point: ```tsx import Markdown, { compiler, parser, astToJSX } from 'markdown-to-jsx/react' const jsxElement = compiler('# Hello world') function App() { return } /** Or use parser + astToJSX */ const ast = parser('# Hello world') const jsxElement2 = astToJSX(ast) ``` ##### React Server Components (RSC) The `Markdown` component automatically detects whether it's running in a React Server Component (RSC) or client environment and adapts accordingly. No 'use client' directive is required. **Server Component (RSC) usage:** ```tsx // Server Component - works automatically import Markdown from 'markdown-to-jsx/react' export default async function Page() { const content = await fetchMarkdownContent() return {content} } ``` **Client Component usage:** ```tsx // Client Component - also works automatically 'use client' import Markdown from 'markdown-to-jsx/react' export function ClientMarkdown({ content }: { content: string }) { return {content} } ``` **Notes:** - `MarkdownProvider` and `MarkdownContext` are client-only and become no-ops in RSC environments - RSC rendering provides better performance by avoiding client-side hydration - The component maintains identical output in both environments - No migration needed for existing code #### React Native For React Native usage, import from the `/native` entry point: ```tsx import Markdown, { compiler, parser, astToNative } from 'markdown-to-jsx/native' import { View, Text, StyleSheet, Linking } from 'react-native' const nativeElement = compiler('# Hello world', { styles: { heading1: { fontSize: 32, fontWeight: 'bold' }, paragraph: { marginVertical: 8 }, link: { color: 'blue', textDecorationLine: 'underline' }, }, onLinkPress: url => { Linking.openURL(url) }, }) const markdown = `# Hello world This is a [link](https://example.com) with **bold** and *italic* text. ` function App() { return ( { Linking.openURL(url) }, }} /> ) } ``` **React Native-specific options:** - `onLinkPress?: (url: string, title?: string) => void` - Custom handler for link presses (defaults to `Linking.openURL`) - `onLinkLongPress?: (url: string, title?: string) => void` - Handler for link long presses - `styles?: Partial>>` - Style overrides for each element type - `wrapperProps?: ViewProps | TextProps` - Props for the wrapper component (defaults to `View` for block, `Text` for inline) **HTML Tag Mapping:** HTML tags are automatically mapped to React Native components: - `` → `Image` component - Block elements (`
`, `
`, `
`, `
`, `