, ,
,
,,
A very fast and versatile markdown toolchain. AST, React, React Native, SolidJS, Vue, Markdown, and HTML output available with full customization.
npm install 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 support; see Syntax highlighting for instructions on setting up highlight.js.
- Upgrading
- From v8.x to v9.x
- From v7.x to v8.x
- Installation
- Usage
- Entry Points
- Main
- React
- React Server Components RSC
- React Native
- SolidJS
- Vue.js
- HTML
- Markdown
- Library Options
- All Options
- options.createElement
- options.forceWrapper
- options.overrides
- options.evalUnserializableExpressions
- options.ignoreHTMLBlocks
- options.renderRule
- options.sanitizer
- options.slugify
- options.wrapper
- Other useful recipes
- options.wrapperProps
- Syntax highlighting
- Handling shortcodes
- Streaming Markdown
- Usage with Preact
- AST Anatomy
- Node Types
- Example AST Structure
- Type Checking
- Gotchas
- Changelog
- Donate
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
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
Install markdown-to-jsx with your favorite package manager.
`shell`
npm i markdown-to-jsx
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(
/*
renders:
\* 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.
$3
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 worldThis is a link with bold and italic text.
function App() {
return (
options={{
styles: StyleSheet.create({
heading1: { fontSize: 32, fontWeight: 'bold' },
paragraph: { marginVertical: 8 },
link: { color: 'blue', textDecorationLine: 'underline' },
}),
onLinkPress: url => {
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 pressesstyles?: Partial
- - Style overrides for each element typewrapperProps?: 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 (
, , , ,
,
,,