An open API service indexing awesome lists of open source software.

https://github.com/quantizor/markdown-to-jsx

A very fast and versatile markdown toolchain. Output to AST, React, React Native, SolidJS, Vue, HTML, and more!
https://github.com/quantizor/markdown-to-jsx

ast gfm jsx markdown react solidjs vue vuejs

Last synced: 28 days ago
JSON representation

A very fast and versatile markdown toolchain. Output to AST, React, React Native, SolidJS, Vue, HTML, and more!

Awesome Lists containing this project

README

          

[![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('alert("xss")') // <script>

/** Restore old behavior */
compiler('alert("xss")', { 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 (`

`, ``, ``, `
`, `