Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-markdown

Package Overview
Dependencies
Maintainers
2
Versions
92
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-markdown - npm Package Compare versions

Comparing version 8.0.7 to 9.0.0

lib/index.d.ts

10

index.d.ts

@@ -1,4 +0,6 @@

export {uriTransformer} from './lib/uri-transformer.js'
export {ReactMarkdown as default} from './lib/react-markdown.js'
export type Options = import('./lib/react-markdown.js').ReactMarkdownOptions
export type Components = import('./lib/ast-to-react.js').Components
export type ExtraProps = import('hast-util-to-jsx-runtime').ExtraProps;
export type AllowElement = import('./lib/index.js').AllowElement;
export type Components = import('./lib/index.js').Components;
export type Options = import('./lib/index.js').Options;
export type UrlTransform = import('./lib/index.js').UrlTransform;
export { Markdown as default, defaultUrlTransform } from "./lib/index.js";

11

index.js
/**
* @typedef {import('./lib/react-markdown.js').ReactMarkdownOptions} Options
* @typedef {import('./lib/ast-to-react.js').Components} Components
* @typedef {import('hast-util-to-jsx-runtime').ExtraProps} ExtraProps
* @typedef {import('./lib/index.js').AllowElement} AllowElement
* @typedef {import('./lib/index.js').Components} Components
* @typedef {import('./lib/index.js').Options} Options
* @typedef {import('./lib/index.js').UrlTransform} UrlTransform
*/
export {uriTransformer} from './lib/uri-transformer.js'
export {ReactMarkdown as default} from './lib/react-markdown.js'
export {Markdown as default, defaultUrlTransform} from './lib/index.js'
{
"name": "react-markdown",
"version": "8.0.7",
"version": "9.0.0",
"description": "React component to render markdown",
"license": "MIT",
"keywords": [
"remark",
"unified",
"markdown",
"ast",
"commonmark",
"component",
"gfm",
"ast",
"markdown",
"react",
"react-component",
"component"
"remark",
"unified"
],

@@ -72,64 +72,60 @@ "repository": "remarkjs/react-markdown",

"type": "module",
"main": "index.js",
"types": "index.d.ts",
"unpkg": "react-markdown.min.js",
"exports": "./index.js",
"files": [
"lib/",
"index.d.ts",
"index.js",
"react-markdown.min.js"
"index.js"
],
"dependencies": {
"@types/hast": "^2.0.0",
"@types/prop-types": "^15.0.0",
"@types/unist": "^2.0.0",
"comma-separated-tokens": "^2.0.0",
"hast-util-whitespace": "^2.0.0",
"prop-types": "^15.0.0",
"property-information": "^6.0.0",
"react-is": "^18.0.0",
"remark-parse": "^10.0.0",
"remark-rehype": "^10.0.0",
"space-separated-tokens": "^2.0.0",
"style-to-object": "^0.4.0",
"unified": "^10.0.0",
"unist-util-visit": "^4.0.0",
"vfile": "^5.0.0"
"@types/hast": "^3.0.0",
"devlop": "^1.0.0",
"hast-util-to-jsx-runtime": "^2.0.0",
"html-url-attributes": "^3.0.0",
"mdast-util-to-hast": "^13.0.0",
"micromark-util-sanitize-uri": "^2.0.0",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.0.0",
"unified": "^11.0.0",
"unist-util-visit": "^5.0.0",
"vfile": "^6.0.0"
},
"peerDependencies": {
"@types/react": ">=16",
"react": ">=16"
"@types/react": ">=18",
"react": ">=18"
},
"devDependencies": {
"@types/node": "^18.0.0",
"@types/node": "^20.0.0",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/react-is": "^17.0.0",
"c8": "^7.0.0",
"esbuild": "^0.17.0",
"eslint-config-xo-react": "^0.27.0",
"eslint-plugin-es": "^4.0.0",
"c8": "^8.0.0",
"esbuild": "^0.19.0",
"eslint-plugin-react": "^7.0.0",
"eslint-plugin-react-hooks": "^4.0.0",
"eslint-plugin-security": "^1.0.0",
"prettier": "^2.0.0",
"prettier": "^3.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"rehype-raw": "^6.0.0",
"rehype-raw": "^7.0.0",
"remark-cli": "^11.0.0",
"remark-gfm": "^3.0.0",
"remark-gfm": "^4.0.0",
"remark-preset-wooorm": "^9.0.0",
"remark-toc": "^8.0.0",
"remark-toc": "^9.0.0",
"type-coverage": "^2.0.0",
"typescript": "^5.0.0",
"xo": "^0.54.0"
"xo": "^0.56.0"
},
"scripts": {
"build": "tsc --build --clean && tsc --build && type-coverage",
"format": "remark . --frail --output --quiet && prettier . --log-level warn --write && xo --fix",
"prepack": "npm run build && npm run format",
"build": "tsc --build --clean && tsc --build && type-coverage && esbuild index.js --bundle --minify --target=es2015 --outfile=react-markdown.min.js --global-name=ReactMarkdown --banner:js=\"(function (g, f) {typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = f() : typeof define === 'function' && define.amd ? define([], f) : (g = typeof globalThis !== 'undefined' ? globalThis : g || self, g.ReactMarkdown = f()); }(this, (function () { 'use strict';\" --footer:js=\"return ReactMarkdown;})));\"",
"format": "remark . -qfo --ignore-pattern test/ && prettier . -w --loglevel warn && xo --fix",
"test-api": "node --no-warnings --experimental-loader=./test/loader.js --conditions development test/test.jsx",
"test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api",
"test": "npm run build && npm run format && npm run test-coverage"
"test": "npm run build && npm run format && npm run test-coverage",
"test-api": "node --conditions development --experimental-loader=./script/load-jsx.js --no-warnings test.jsx",
"test-coverage": "c8 --100 --exclude script/ --reporter lcov npm run test-api"
},
"prettier": {
"bracketSpacing": false,
"singleQuote": true,
"semi": false,
"tabWidth": 2,
"trailingComma": "none",
"useTabs": false
},
"remarkConfig": {

@@ -139,3 +135,3 @@ "plugins": [

[
"remark-gfm",
"./node_modules/remark-preset-wooorm/node_modules/remark-gfm/index.js",
{

@@ -158,50 +154,26 @@ "tablePipeAlign": false

"detail": true,
"strict": true,
"ignoreCatch": true,
"#": "below is ignored because some proptypes will `any`",
"ignoreFiles": [
"lib/react-markdown.d.ts",
"index.d.ts"
]
"strict": true
},
"prettier": {
"tabWidth": 2,
"useTabs": false,
"singleQuote": true,
"bracketSpacing": false,
"semi": false,
"trailingComma": "none"
},
"xo": {
"prettier": true,
"extends": "xo-react",
"envs": [
"shared-node-browser"
],
"extends": "plugin:react/jsx-runtime",
"overrides": [
{
"files": [
"lib/**/*.js"
"**/*.jsx"
],
"extends": [
"plugin:es/restrict-to-es2019",
"plugin:security/recommended"
],
"rules": {
"complexity": "off",
"security/detect-object-injection": "off"
"no-unused-vars": "off"
}
},
{
"files": [
"test/**/*.jsx"
],
"rules": {
"n/file-extension-in-import": "off",
"react/no-children-prop": "off",
"react/prop-types": "off"
}
}
]
],
"prettier": true,
"rules": {
"complexity": "off",
"n/file-extension-in-import": "off"
}
}
}

@@ -21,9 +21,9 @@ <!--

* [x] **[safe][security] by default**
* [x] **[safe][section-security] by default**
(no `dangerouslySetInnerHTML` or XSS attacks)
* [x] **[components][]**
* [x] **[components][section-components]**
(pass your own component to use instead of `<h2>` for `## hi`)
* [x] **[plugins][]**
* [x] **[plugins][section-plugins]**
(many plugins you can pick and choose from)
* [x] **[compliant][syntax]**
* [x] **[compliant][section-syntax]**
(100% to CommonMark, 100% to GFM with a plugin)

@@ -38,4 +38,9 @@

* [API](#api)
* [`props`](#props)
* [`uriTransformer`](#uritransformer)
* [`Markdown`](#markdown)
* [`defaultUrlTransform(url)`](#defaulturltransformurl)
* [`AllowElement`](#allowelement)
* [`Components`](#components)
* [`ExtraProps`](#extraprops)
* [`Options`](#options)
* [`UrlTransform`](#urltransform)
* [Examples](#examples)

@@ -53,2 +58,3 @@ * [Use a plugin](#use-a-plugin)

* [Appendix B: Components](#appendix-b-components)
* [Appendix C: line endings in markdown (and JSX)](#appendix-c-line-endings-in-markdown-and-jsx)
* [Security](#security)

@@ -63,6 +69,6 @@ * [Related](#related)

that it’ll safely render to React elements.
You can pass plugins to change how markdown is transformed to React elements and
pass components that will be used instead of normal HTML elements.
You can pass plugins to change how markdown is transformed and pass components
that will be used instead of normal HTML elements.
* to learn markdown, see this [cheatsheet and tutorial][cheat]
* to learn markdown, see this [cheatsheet and tutorial][commonmark-help]
* to try out `react-markdown`, see [our demo][demo]

@@ -73,13 +79,11 @@

There are other ways to use markdown in React out there so why use this one?
The two main reasons are that they often rely on `dangerouslySetInnerHTML` or
have bugs with how they handle markdown.
`react-markdown` uses a syntax tree to build the virtual dom which allows for
updating only the changing DOM instead of completely overwriting.
`react-markdown` is 100% CommonMark compliant and has plugins to support other
syntax extensions (such as GFM).
The three main reasons are that they often rely on `dangerouslySetInnerHTML`,
have bugs with how they handle markdown, or don’t let you swap elements for
components.
`react-markdown` builds a virtual DOM, so React only replaces what changed,
from a syntax tree.
That’s supported because we use [unified][], specifically [remark][] for
markdown and [rehype][] for HTML, which are popular tools to transform content
with plugins.
These features are supported because we use [unified][], specifically [remark][]
for markdown and [rehype][] for HTML, which are popular tools to transform
content with plugins.
This package focusses on making it easy for beginners to safely use markdown in

@@ -95,3 +99,3 @@ React.

This package is [ESM only][esm].
In Node.js (version 12.20+, 14.14+, or 16.0+), install with [npm][]:
In Node.js (version 16+), install with [npm][]:

@@ -105,3 +109,3 @@ ```sh

```js
import ReactMarkdown from 'https://esm.sh/react-markdown@7'
import Markdown from 'https://esm.sh/react-markdown@9'
```

@@ -113,3 +117,3 @@

<script type="module">
import ReactMarkdown from 'https://esm.sh/react-markdown@7?bundle'
import Markdown from 'https://esm.sh/react-markdown@9?bundle'
</script>

@@ -124,6 +128,8 @@ ```

import React from 'react'
import ReactMarkdown from 'react-markdown'
import ReactDom from 'react-dom'
import Markdown from 'react-markdown'
ReactDom.render(<ReactMarkdown># Hello, *world*!</ReactMarkdown>, document.body)
const markdown = '# Hi, *Pluto*!'
ReactDom.render(<Markdown>{markdown}</Markdown>, document.body)
```

@@ -136,3 +142,3 @@

<h1>
Hello, <em>world</em>!
Hi, <em>Pluto</em>!
</h1>

@@ -144,4 +150,4 @@ ```

Here is an example that shows passing the markdown as a string and how
to use a plugin ([`remark-gfm`][gfm], which adds support for strikethrough,
tables, tasklists and URLs directly):
to use a plugin ([`remark-gfm`][remark-gfm], which adds support for
footnotes, strikethrough, tables, tasklists and URLs directly):

@@ -151,9 +157,9 @@ ```jsx

import ReactDom from 'react-dom'
import ReactMarkdown from 'react-markdown'
import Markdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
const markdown = `Just a link: https://reactjs.com.`
const markdown = `Just a link: www.nasa.gov.`
ReactDom.render(
<ReactMarkdown children={markdown} remarkPlugins={[remarkGfm]} />,
<Markdown remarkPlugins={[remarkGfm]}>{markdown}</Markdown>,
document.body

@@ -168,3 +174,3 @@ )

<p>
Just a link: <a href="https://reactjs.com">https://reactjs.com</a>.
Just a link: <a href="http://www.nasa.gov">www.nasa.gov</a>.
</p>

@@ -178,60 +184,132 @@ ```

This package exports the following identifier:
[`uriTransformer`][uri-transformer].
The default export is `ReactMarkdown`.
[`defaultUrlTransform`][api-default-url-transform].
The default export is [`Markdown`][api-markdown].
### `props`
### `Markdown`
* `children` (`string`, default: `''`)\
markdown to parse
* `components` (`Record<string, Component>`, default: `{}`)\
object mapping tag names to React components
* `remarkPlugins` (`Array<Plugin>`, default: `[]`)\
list of [remark plugins][remark-plugins] to use
* `rehypePlugins` (`Array<Plugin>`, default: `[]`)\
list of [rehype plugins][rehype-plugins] to use
* `remarkRehypeOptions` (`Object?`, default: `undefined`)\
options to pass through to [`remark-rehype`][remark-rehype]
* `className` (`string?`)\
wrap the markdown in a `div` with this class name
* `skipHtml` (`boolean`, default: `false`)\
ignore HTML in markdown completely
* `sourcePos` (`boolean`, default: `false`)\
pass a prop to all components with a serialized position
(`data-sourcepos="3:1-3:13"`)
* `rawSourcePos` (`boolean`, default: `false`)\
pass a prop to all components with their [position][]
(`sourcePosition: {start: {line: 3, column: 1}, end:…}`)
* `includeElementIndex` (`boolean`, default: `false`)\
pass the `index` (number of elements before it) and `siblingCount` (number
of elements in parent) as props to all components
* `allowedElements` (`Array<string>`, default: `undefined`)\
tag names to allow (can’t combine w/ `disallowedElements`), all tag names
are allowed by default
* `disallowedElements` (`Array<string>`, default: `undefined`)\
tag names to disallow (can’t combine w/ `allowedElements`), all tag names
are allowed by default
* `allowElement` (`(element, index, parent) => boolean?`, optional)\
function called to check if an element is allowed (when truthy) or not,
`allowedElements` or `disallowedElements` is used first!
* `unwrapDisallowed` (`boolean`, default: `false`)\
extract (unwrap) the children of not allowed elements, by default, when
`strong` is disallowed, it and it’s children are dropped, but with
`unwrapDisallowed` the element itself is replaced by its children
* `linkTarget` (`string` or `(href, children, title) => string`, optional)\
target to use on links (such as `_blank` for `<a target="_blank"…`)
* `transformLinkUri` (`(href, children, title) => string`, default:
[`uriTransformer`][uri-transformer], optional)\
change URLs on links, pass `null` to allow all URLs, see [security][]
* `transformImageUri` (`(src, alt, title) => string`, default:
[`uriTransformer`][uri-transformer], optional)\
change URLs on images, pass `null` to allow all URLs, see [security][]
Component to render markdown.
### `uriTransformer`
###### Parameters
Our default URL transform, which you can overwrite (see props above).
It’s given a URL and cleans it, by allowing only `http:`, `https:`, `mailto:`,
and `tel:` URLs, absolute paths (`/example.png`), and hashes (`#some-place`).
* `options` ([`Options`][api-options])
— props
See the [source code here][uri].
###### Returns
React element (`JSX.Element`).
### `defaultUrlTransform(url)`
Make a URL safe.
###### Parameters
* `url` (`string`)
— URL
###### Returns
Safe URL (`string`).
### `AllowElement`
Filter elements (TypeScript type).
###### Parameters
* `node` ([`Element` from `hast`][hast-element])
— element to check
* `index` (`number | undefined`)
— index of `element` in `parent`
* `parent` ([`Node` from `hast`][hast-node])
— parent of `element`
###### Returns
Whether to allow `element` (`boolean`, optional).
### `Components`
Map tag names to components (TypeScript type).
###### Type
```ts
import type {Element} from 'hast'
type Components = Partial<{
[TagName in keyof JSX.IntrinsicElements]:
// Class component:
| (new (props: JSX.IntrinsicElements[TagName] & ExtraProps) => JSX.ElementClass)
// Function component:
| ((props: JSX.IntrinsicElements[TagName] & ExtraProps) => JSX.Element | string | null | undefined)
// Tag name:
| keyof JSX.IntrinsicElements
}>
```
### `ExtraProps`
Extra fields we pass to components (TypeScript type).
###### Fields
* `node` ([`Element` from `hast`][hast-element], optional)
— original node
### `Options`
Configuration (TypeScript type).
###### Fields
* `allowElement` ([`AllowElement`][api-allow-element], optional)
— filter elements;
`allowedElements` / `disallowedElements` is used first
* `allowedElements` (`Array<string>`, default: all tag names)
— tag names to allow;
cannot combine w/ `disallowedElements`
* `children` (`string`, optional)
— markdown
* `className` (`string`, optional)
— wrap in a `div` with this class name
* `components` ([`Components`][api-components], optional)
— map tag names to components
* `disallowedElements` (`Array<string>`, default: `[]`)
— tag names to disallow;
cannot combine w/ `allowedElements`
* `rehypePlugins` (`Array<Plugin>`, optional)
— list of [rehype plugins][rehype-plugins] to use
* `remarkPlugins` (`Array<Plugin>`, optional)
— list of [remark plugins][remark-plugins] to use
* `remarkRehypeOptions` ([`Options` from
`remark-rehype`][remark-rehype-options], optional)
— options to pass through to `remark-rehype`
* `skipHtml` (`boolean`, default: `false`)
— ignore HTML in markdown completely
* `unwrapDisallowed` (`boolean`, default: `false`)
— extract (unwrap) what’s in disallowed elements;
normally when say `strong` is not allowed, it and it’s children are dropped,
with `unwrapDisallowed` the element itself is replaced by its children
* `urlTransform` ([`UrlTransform`][api-url-transform], default:
[`defaultUrlTransform`][api-default-url-transform])
— change URLs
### `UrlTransform`
Transform URLs (TypeScript type).
###### Parameters
* `url` (`string`)
— URL
* `key` (`string`, example: `'href'`)
— property name
* `node` ([`Element` from `hast`][hast-element])
— element to check
###### Returns
Transformed URL (`string`, optional).
## Examples

@@ -242,9 +320,9 @@

This example shows how to use a remark plugin.
In this case, [`remark-gfm`][gfm], which adds support for strikethrough, tables,
tasklists and URLs directly:
In this case, [`remark-gfm`][remark-gfm], which adds support for strikethrough,
tables, tasklists and URLs directly:
```jsx
import React from 'react'
import ReactMarkdown from 'react-markdown'
import ReactDom from 'react-dom'
import Markdown from 'react-markdown'
import remarkGfm from 'remark-gfm'

@@ -267,3 +345,3 @@

ReactDom.render(
<ReactMarkdown children={markdown} remarkPlugins={[remarkGfm]} />,
<Markdown remarkPlugins={[remarkGfm]}>{markdown}</Markdown>,
document.body

@@ -287,9 +365,9 @@ )

</blockquote>
<ul>
<ul className="contains-task-list">
<li>Lists</li>
<li>
<input checked={false} readOnly={true} type="checkbox" /> todo
<li className="task-list-item">
<input type="checkbox" disabled /> todo
</li>
<li>
<input checked={true} readOnly={true} type="checkbox" /> done
<li className="task-list-item">
<input type="checkbox" disabled checked /> done
</li>

@@ -301,4 +379,4 @@ </ul>

<tr>
<td>a</td>
<td>b</td>
<th>a</th>
<th>b</th>
</tr>

@@ -317,14 +395,17 @@ </thead>

second.
[`remark-gfm`][gfm] has an option to allow only double tildes for strikethrough:
[`remark-gfm`][remark-gfm] has an option to allow only double tildes for
strikethrough:
```jsx
import React from 'react'
import ReactMarkdown from 'react-markdown'
import ReactDom from 'react-dom'
import Markdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
const markdown = 'This ~is not~ strikethrough, but ~~this is~~!'
ReactDom.render(
<ReactMarkdown remarkPlugins={[[remarkGfm, {singleTilde: false}]]}>
This ~is not~ strikethrough, but ~~this is~~!
</ReactMarkdown>,
<Markdown remarkPlugins={[[remarkGfm, {singleTilde: false}]]}>
{markdown}
</Markdown>,
document.body

@@ -353,6 +434,8 @@ )

<!-- To do: currently broken on actual ESM; let’s find an alternative? -->
```jsx
import React from 'react'
import ReactDom from 'react-dom'
import ReactMarkdown from 'react-markdown'
import Markdown from 'react-markdown'
import {Prism as SyntaxHighlighter} from 'react-syntax-highlighter'

@@ -370,10 +453,11 @@ import {dark} from 'react-syntax-highlighter/dist/esm/styles/prism'

ReactDom.render(
<ReactMarkdown
<Markdown
children={markdown}
components={{
code({node, inline, className, children, ...props}) {
code(props) {
const {children, className, node, ...rest} = props
const match = /language-(\w+)/.exec(className || '')
return !inline && match ? (
return match ? (
<SyntaxHighlighter
{...props}
{...rest}
children={String(children).replace(/\n$/, '')}

@@ -385,3 +469,3 @@ style={dark}

) : (
<code {...props} className={className}>
<code {...rest} className={className}>
{children}

@@ -413,5 +497,5 @@ </code>

This example shows how a syntax extension (through [`remark-math`][math])
This example shows how a syntax extension (through [`remark-math`][remark-math])
is used to support math in markdown, and a transform plugin
([`rehype-katex`][katex]) to render that math.
([`rehype-katex`][rehype-katex]) to render that math.

@@ -421,14 +505,13 @@ ```jsx

import ReactDom from 'react-dom'
import ReactMarkdown from 'react-markdown'
import Markdown from 'react-markdown'
import rehypeKatex from 'rehype-katex'
import remarkMath from 'remark-math'
import rehypeKatex from 'rehype-katex'
import 'katex/dist/katex.min.css' // `rehype-katex` does not import the CSS for you
const markdown = `The lift coefficient ($C_L$) is a dimensionless coefficient.`
ReactDom.render(
<ReactMarkdown
children={`The lift coefficient ($C_L$) is a dimensionless coefficient.`}
remarkPlugins={[remarkMath]}
rehypePlugins={[rehypeKatex]}
/>,
<Markdown remarkPlugins={[remarkMath]} rehypePlugins={[rehypeKatex]}>
{markdown}
</Markdown>,
document.body

@@ -444,11 +527,9 @@ )

The lift coefficient (
<span className="math math-inline">
<span className="katex">
<span className="katex-mathml">
<math xmlns="http://www.w3.org/1998/Math/MathML">{/* … */}</math>
</span>
<span className="katex-html" aria-hidden="true">
{/* … */}
</span>
<span className="katex">
<span className="katex-mathml">
<math xmlns="http://www.w3.org/1998/Math/MathML">{/* … */}</math>
</span>
<span className="katex-html" aria-hidden="true">
{/* … */}
</span>
</span>

@@ -488,11 +569,19 @@ ) is a dimensionless coefficient.

This package is fully typed with [TypeScript][].
It exports `Options` and `Components` types, which specify the interface of the
accepted props and components.
It exports the additional types
[`AllowElement`][api-allow-element],
[`ExtraProps`][api-extra-props],
[`Components`][api-components],
[`Options`][api-options], and
[`UrlTransform`][api-url-transform].
## Compatibility
Projects maintained by the unified collective are compatible with all maintained
Projects maintained by the unified collective are compatible with maintained
versions of Node.js.
As of now, that is Node.js 12.20+, 14.14+, and 16.0+.
Our projects sometimes work with older versions, but this is not guaranteed.
When we cut a new major release, we drop support for unmaintained versions of
Node.
This means we try to keep the current release line, `react-markdown@^9`,
compatible with Node.js 16.
They work in all modern browsers (essentially: everything not IE 11).

@@ -538,3 +627,3 @@ You can use a bundler (such as esbuild, webpack, or Rollup) to use this package

can spare the bundle size (±60kb minzipped), then you can use
[`rehype-raw`][raw]:
[`rehype-raw`][rehype-raw]:

@@ -544,6 +633,6 @@ ```jsx

import ReactDom from 'react-dom'
import ReactMarkdown from 'react-markdown'
import Markdown from 'react-markdown'
import rehypeRaw from 'rehype-raw'
const input = `<div class="note">
const markdown = `<div class="note">

@@ -555,3 +644,3 @@ Some *emphasis* and <strong>strong</strong>!

ReactDom.render(
<ReactMarkdown rehypePlugins={[rehypeRaw]} children={input} />,
<Markdown rehypePlugins={[rehypeRaw]}>{markdown}</Markdown>,
document.body

@@ -565,4 +654,6 @@ )

```jsx
<div class="note">
<p>Some <em>emphasis</em> and <strong>strong</strong>!</p>
<div className="note">
<p>
Some <em>emphasis</em> and <strong>strong</strong>!
</p>
</div>

@@ -574,3 +665,3 @@ ```

**Note**: HTML in markdown is still bound by how [HTML works in
CommonMark][cm-html].
CommonMark][commonmark-html].
Make sure to use blank lines around block-level HTML that again contains

@@ -584,3 +675,3 @@ markdown!

```jsx
<ReactMarkdown
<Markdown
components={{

@@ -590,3 +681,6 @@ // Map `h1` (`# heading`) to use `h2`s.

// Rewrite `em`s (`*like so*`) to `i` with a red foreground color.
em: ({node, ...props}) => <i style={{color: 'red'}} {...props} />
em(props) {
const {node, ...rest} = props
return <i style={{color: 'red'}} {...rest} />
}
}}

@@ -601,4 +695,4 @@ />

`ul`.
With [`remark-gfm`][gfm], you can also use: `del`, `input`, `table`, `tbody`,
`td`, `th`, `thead`, and `tr`.
With [`remark-gfm`][remark-gfm], you can also use `del`, `input`, `table`,
`tbody`, `td`, `th`, `thead`, and `tr`.
Other remark or rehype plugins that add support for new constructs will also

@@ -610,69 +704,71 @@ work with `react-markdown`.

etc.
There are some extra props passed.
* `code`
* `inline` (`boolean?`)
— set to `true` for inline code
* `className` (`string?`)
— set to `language-js` or so when using ` ```js `
* `h1`, `h2`, `h3`, `h4`, `h5`, `h6`
* `level` (`number` between 1 and 6)
— heading rank
* `input` (when using [`remark-gfm`][gfm])
* `checked` (`boolean`)
— whether the item is checked
* `disabled` (`true`)
* `type` (`'checkbox'`)
* `li`
* `index` (`number`)
— number of preceding items (so first gets `0`, etc.)
* `ordered` (`boolean`)
— whether the parent is an `ol` or not
* `checked` (`boolean?`)
— `null` normally, `boolean` when using [`remark-gfm`][gfm]’s tasklists
* `className` (`string?`)
— set to `task-list-item` when using [`remark-gfm`][gfm] and the
item1 is a tasklist
* `ol`, `ul`
* `depth` (`number`)
— number of ancestral lists (so first gets `0`, etc.)
* `ordered` (`boolean`)
— whether it’s an `ol` or not
* `className` (`string?`)
— set to `contains-task-list` when using [`remark-gfm`][gfm] and the
list contains one or more tasklists
* `td`, `th` (when using [`remark-gfm`][gfm])
* `style` (`Object?`)
— something like `{textAlign: 'left'}` depending on how the cell is
aligned
* `isHeader` (`boolean`)
— whether it’s a `th` or not
* `tr` (when using [`remark-gfm`][gfm])
* `isHeader` (`boolean`)
— whether it’s in the `thead` or not
Every component will receive a `node`.
This is the original [`Element` from `hast`][hast-element] element being turned
into a React element.
Every component will receive a `node` (`Object`).
This is the original [hast](https://github.com/syntax-tree/hast) element being
turned into a React element.
## Appendix C: line endings in markdown (and JSX)
Every element will receive a `key` (`string`).
See [React’s docs](https://reactjs.org/docs/lists-and-keys.html#keys) for more
info.
You might have trouble with how line endings work in markdown and JSX.
We recommend the following, which solves all line ending problems:
Optionally, components will also receive:
```jsx
// If you write actual markdown in your code, put your markdown in a variable;
// **do not indent markdown**:
const markdown = `
# This is perfect!
`
* `data-sourcepos` (`string`)
— see `sourcePos` option
* `sourcePosition` (`Object`)
— see `rawSourcePos` option
* `index` and `siblingCount` (`number`)
— see `includeElementIndex` option
* `target` on `a` (`string`)
— see `linkTarget` option
// Pass the value as an expresion as an only child:
<Markdown>{markdown}</Markdown>
```
👆 That works.
Read on for what doesn’t and why that is.
You might try to write markdown directly in your JSX and find that it **does
not** work:
```jsx
<Markdown>
# Hi
This is **not** a paragraph.
</Markdown>
```
The is because in JSX the whitespace (including line endings) is collapsed to
a single space.
So the above example is equivalent to:
```jsx
<Markdown> # Hi This is **not** a paragraph. </Markdown>
```
Instead, to pass markdown to `Markdown`, you can use an expression:
with a template literal:
```jsx
<Markdown>{`
# Hi
This is a paragraph.
`}</Markdown>
```
Template literals have another potential problem, because they keep whitespace
(including indentation) inside them.
That means that the following **does not** turn into a heading:
```jsx
<Markdown>{`
# This is **not** a heading, it’s an indented code block
`}</Markdown>
```
## Security
Use of `react-markdown` is secure by default.
Overwriting `transformLinkUri` or `transformImageUri` to something insecure will
open you up to XSS vectors.
Overwriting `urlTransform` to something insecure will open you up to XSS
vectors.
Furthermore, the `remarkPlugins`, `rehypePlugins`, and `components` you use may

@@ -682,3 +778,3 @@ be insecure.

To make sure the content is completely safe, even after what plugins do,
use [`rehype-sanitize`][sanitize].
use [`rehype-sanitize`][rehype-sanitize].
It lets you define your own schema of what is and isn’t allowed.

@@ -688,8 +784,8 @@

* [`MDX`](https://github.com/mdx-js/mdx)
* [`MDX`][mdx]
— JSX *in* markdown
* [`remark-gfm`](https://github.com/remarkjs/remark-gfm)
* [`remark-gfm`][remark-gfm]
— add support for GitHub flavored markdown support
* [`react-remark`][react-remark]
— modern hook based alternative
— hook based alternative
* [`rehype-react`][rehype-react]

@@ -724,5 +820,5 @@ — turn HTML into React elements

[size-badge]: https://img.shields.io/bundlephobia/minzip/react-markdown.svg
[size-badge]: https://img.shields.io/bundlejs/size/react-markdown
[size]: https://bundlephobia.com/result?p=react-markdown
[size]: https://bundlejs.com/?q=react-markdown

@@ -741,2 +837,4 @@ [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg

[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
[esmsh]: https://esm.sh

@@ -746,7 +844,7 @@

[contributing]: https://github.com/remarkjs/.github/blob/HEAD/contributing.md
[coc]: https://github.com/remarkjs/.github/blob/main/code-of-conduct.md
[support]: https://github.com/remarkjs/.github/blob/HEAD/support.md
[contributing]: https://github.com/remarkjs/.github/blob/main/contributing.md
[coc]: https://github.com/remarkjs/.github/blob/HEAD/code-of-conduct.md
[support]: https://github.com/remarkjs/.github/blob/main/support.md

@@ -757,68 +855,78 @@ [license]: license

[micromark]: https://github.com/micromark/micromark
[awesome-remark]: https://github.com/remarkjs/awesome-remark
[remark]: https://github.com/remarkjs/remark
[awesome-rehype]: https://github.com/rehypejs/awesome-rehype
[demo]: https://remarkjs.github.io/react-markdown/
[commonmark-help]: https://commonmark.org/help/
[position]: https://github.com/syntax-tree/unist#position
[commonmark-html]: https://spec.commonmark.org/0.30/#html-blocks
[gfm]: https://github.com/remarkjs/remark-gfm
[hast-element]: https://github.com/syntax-tree/hast#element
[math]: https://github.com/remarkjs/remark-math
[hast-node]: https://github.com/syntax-tree/hast#nodes
[katex]: https://github.com/remarkjs/remark-math/tree/main/packages/rehype-katex
[mdx]: https://github.com/mdx-js/mdx/
[raw]: https://github.com/rehypejs/rehype-raw
[micromark]: https://github.com/micromark/micromark
[sanitize]: https://github.com/rehypejs/rehype-sanitize
[react]: http://reactjs.org
[remark-plugins]: https://github.com/remarkjs/remark/blob/main/doc/plugins.md#list-of-plugins
[react-remark]: https://github.com/remarkjs/react-remark
[react-syntax-highlighter]: https://github.com/react-syntax-highlighter/react-syntax-highlighter
[rehype]: https://github.com/rehypejs/rehype
[rehype-katex]: https://github.com/remarkjs/remark-math/tree/main/packages/rehype-katex
[rehype-plugin]: https://github.com/topics/rehype-plugin
[rehype-plugins]: https://github.com/rehypejs/rehype/blob/main/doc/plugins.md#list-of-plugins
[remark-rehype]: https://github.com/remarkjs/remark-rehype
[rehype-react]: https://github.com/rehypejs/rehype-react
[awesome-remark]: https://github.com/remarkjs/awesome-remark
[rehype-raw]: https://github.com/rehypejs/rehype-raw
[awesome-rehype]: https://github.com/rehypejs/awesome-rehype
[rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize
[remark-plugin]: https://github.com/topics/remark-plugin
[remark]: https://github.com/remarkjs/remark
[rehype-plugin]: https://github.com/topics/rehype-plugin
[remark-gfm]: https://github.com/remarkjs/remark-gfm
[cm-html]: https://spec.commonmark.org/0.30/#html-blocks
[remark-math]: https://github.com/remarkjs/remark-math
[uri]: https://github.com/remarkjs/react-markdown/blob/main/lib/uri-transformer.js
[remark-plugin]: https://github.com/topics/remark-plugin
[uri-transformer]: #uritransformer
[remark-plugins]: https://github.com/remarkjs/remark/blob/main/doc/plugins.md#list-of-plugins
[react]: http://reactjs.org
[remark-rehype-options]: https://github.com/remarkjs/remark-rehype#options
[cheat]: https://commonmark.org/help/
[unified]: https://github.com/unifiedjs/unified
[rehype]: https://github.com/rehypejs/rehype
[typescript]: https://www.typescriptlang.org
[react-remark]: https://github.com/remarkjs/react-remark
[conor]: https://github.com/conorhastings
[rehype-react]: https://github.com/rehypejs/rehype-react
[demo]: https://remarkjs.github.io/react-markdown/
[mdx]: https://github.com/mdx-js/mdx/
[section-components]: #appendix-b-components
[typescript]: https://www.typescriptlang.org
[section-plugins]: #plugins
[security]: #security
[section-security]: #security
[components]: #appendix-b-components
[section-syntax]: #syntax
[plugins]: #plugins
[api-allow-element]: #allowelement
[syntax]: #syntax
[api-components]: #components
[react-syntax-highlighter]: https://github.com/react-syntax-highlighter/react-syntax-highlighter
[api-default-url-transform]: #defaulturltransformurl
[conor]: https://github.com/conorhastings
[api-extra-props]: #extraprops
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
[api-markdown]: #markdown
[api-options]: #options
[api-url-transform]: #urltransform
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc