Skip to content

Commit 4185f06

Browse files
authoredNov 29, 2021
Add improved docs
Closes GH-657 Reviewed-by: Merlijn Vos <merlijn@soverin.net>
1 parent 8e07e9c commit 4185f06

File tree

3 files changed

+245
-89
lines changed

3 files changed

+245
-89
lines changed
 

‎lib/react-markdown.js

+2
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ const deprecated = {
6565
}
6666

6767
/**
68+
* React component to render markdown.
69+
*
6870
* @param {ReactMarkdownOptions} options
6971
* @returns {ReactElement}
7072
*/

‎package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "react-markdown",
33
"version": "7.1.0",
4-
"description": "Render Markdown as React components",
4+
"description": "React component to render markdown",
55
"license": "MIT",
66
"keywords": [
77
"remark",

‎readme.md

+242-88
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
<!--
2+
Notes for maintaining this document:
3+
4+
* Update the link for `cm-html` once in a while
5+
-->
6+
17
# react-markdown
28

39
[![Build][build-badge]][build]
@@ -8,30 +14,98 @@
814
[![Backers][backers-badge]][collective]
915
[![Chat][chat-badge]][chat]
1016

11-
Markdown component for React using [**remark**][remark].
17+
React component to render markdown.
18+
19+
## Feature highlights
20+
21+
* [x] **[safe][security] by default**
22+
(no `dangerouslySetInnerHTML` or XSS attacks)
23+
* [x] **[components][]**
24+
(pass your own component to use instead of `<h2>` for `## hi`)
25+
* [x] **[plugins][]**
26+
(many plugins you can pick and choose from)
27+
* [x] **[compliant][syntax]**
28+
(100% to CommonMark, 100% to GFM with a plugin)
29+
30+
## Contents
31+
32+
* [What is this?](#what-is-this)
33+
* [When should I use this?](#when-should-i-use-this)
34+
* [Install](#install)
35+
* [Use](#use)
36+
* [API](#api)
37+
* [`props`](#props)
38+
* [`uriTransformer`](#uritransformer)
39+
* [Examples](#examples)
40+
* [Use a plugin](#use-a-plugin)
41+
* [Use a plugin with options](#use-a-plugin-with-options)
42+
* [Use custom components (syntax highlight)](#use-custom-components-syntax-highlight)
43+
* [Use remark and rehype plugins (math)](#use-remark-and-rehype-plugins-math)
44+
* [Plugins](#plugins)
45+
* [Syntax](#syntax)
46+
* [Types](#types)
47+
* [Compatibility](#compatibility)
48+
* [Architecture](#architecture)
49+
* [Appendix A: HTML in markdown](#appendix-a-html-in-markdown)
50+
* [Appendix B: Components](#appendix-b-components)
51+
* [Security](#security)
52+
* [Related](#related)
53+
* [Contribute](#contribute)
54+
* [License](#license)
55+
56+
## What is this?
57+
58+
This package is a [React][] component that can be given a string of markdown
59+
that it’ll safely render to React elements.
60+
You can pass plugins to change how markdown is transformed to React elements and
61+
pass components that will be used instead of normal HTML elements.
62+
63+
* to learn markdown, see this [cheatsheet and tutorial][cheat]
64+
* to try out `react-markdown`, see [our demo][demo]
65+
66+
## When should I use this?
67+
68+
There are other ways to use markdown in React out there so why use this one?
69+
The two main reasons are that they often rely on `dangerouslySetInnerHTML` or
70+
have bugs with how they handle markdown.
71+
`react-markdown` uses a syntax tree to build the virtual dom which allows for
72+
updating only the changing DOM instead of completely overwriting.
73+
`react-markdown` is 100% CommonMark compliant and has plugins to support other
74+
syntax extensions (such as GFM).
1275

13-
[Learn markdown here][learn] and [check out the demo here][demo].
76+
These features are supported because we use [unified][], specifically [remark][]
77+
for markdown and [rehype][] for HTML, which are popular tools to transform
78+
content with plugins.
1479

15-
## Install
80+
This package focusses on making it easy for beginners to safely use markdown in
81+
React.
82+
When you’re familiar with unified, you can use a modern hooks based alternative
83+
[`react-remark`][react-remark] or [`rehype-react`][rehype-react] manually.
84+
If you instead want to use JavaScript and JSX *inside* markdown files, use
85+
[MDX][].
1686

17-
This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c):
18-
Node 12+ is needed to use it and it must be `import`ed instead of `require`d.
87+
## Install
1988

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

2292
```sh
2393
npm install react-markdown
2494
```
2595

26-
## Why this one?
96+
In Deno with [Skypack][]:
2797

28-
There are other ways for markdown in React out there so why use this one?
29-
The two main reasons are that they often rely on `dangerouslySetInnerHTML` or
30-
have bugs with how they handle markdown.
31-
`react-markdown` uses a syntax tree to build the virtual dom which allows for
32-
updating only the changing DOM instead of completely overwriting.
33-
`react-markdown` is 100% CommonMark (optionally GFM) compliant and has
34-
extensions to support custom syntax.
98+
```js
99+
import ReactMarkdown from 'https://cdn.skypack.dev/react-markdown@7?dts'
100+
```
101+
102+
In browsers with [Skypack][]:
103+
104+
```html
105+
<script type="module">
106+
import ReactMarkdown from 'https://cdn.skypack.dev/react-markdown@7?min'
107+
</script>
108+
```
35109

36110
## Use
37111

@@ -87,68 +161,70 @@ ReactDom.render(
87161

88162
## API
89163

90-
This package exports the following identifier: `uriTransformer`.
164+
This package exports the following identifier:
165+
[`uriTransformer`][uri-transformer].
91166
The default export is `ReactMarkdown`.
92167

93168
### `props`
94169

95170
* `children` (`string`, default: `''`)\
96-
Markdown to parse
171+
markdown to parse
172+
* `components` (`Record<string, Component>`, default: `{}`)\
173+
object mapping tag names to React components
174+
* `remarkPlugins` (`Array<Plugin>`, default: `[]`)\
175+
list of [remark plugins][remark-plugins] to use
176+
* `rehypePlugins` (`Array<Plugin>`, default: `[]`)\
177+
list of [rehype plugins][rehype-plugins] to use
97178
* `className` (`string?`)\
98-
Wrap the markdown in a `div` with this class name
179+
wrap the markdown in a `div` with this class name
99180
* `skipHtml` (`boolean`, default: `false`)\
100-
Ignore HTML in Markdown completely
181+
ignore HTML in markdown completely
101182
* `sourcePos` (`boolean`, default: `false`)\
102-
Pass a prop to all components with a serialized position
183+
pass a prop to all components with a serialized position
103184
(`data-sourcepos="3:1-3:13"`)
104185
* `rawSourcePos` (`boolean`, default: `false`)\
105-
Pass a prop to all components with their [position][]
186+
pass a prop to all components with their [position][]
106187
(`sourcePosition: {start: {line: 3, column: 1}, end:…}`)
107188
* `includeElementIndex` (`boolean`, default: `false`)\
108-
Pass the `index` (number of elements before it) and `siblingCount` (number
189+
pass the `index` (number of elements before it) and `siblingCount` (number
109190
of elements in parent) as props to all components
110-
* `allowedElements` (`Array.<string>`, default: `undefined`)\
111-
Tag names to allow (can’t combine w/ `disallowedElements`).
112-
By default all elements are allowed
113-
* `disallowedElements` (`Array.<string>`, default: `undefined`)\
114-
Tag names to disallow (can’t combine w/ `allowedElements`).
115-
By default no elements are disallowed
191+
* `allowedElements` (`Array<string>`, default: `undefined`)\
192+
tag names to allow (can’t combine w/ `disallowedElements`), all tag names
193+
are allowed by default
194+
* `disallowedElements` (`Array<string>`, default: `undefined`)\
195+
tag names to disallow (can’t combine w/ `allowedElements`), all tag names
196+
are allowed by default
116197
* `allowElement` (`(element, index, parent) => boolean?`, optional)\
117-
Function called to check if an element is allowed (when truthy) or not.
118-
`allowedElements` / `disallowedElements` is used first!
198+
function called to check if an element is allowed (when truthy) or not,
199+
`allowedElements` or `disallowedElements` is used first!
119200
* `unwrapDisallowed` (`boolean`, default: `false`)\
120-
Extract (unwrap) the children of not allowed elements.
121-
By default, when `strong` is not allowed, it and it’s children is dropped,
122-
but with `unwrapDisallowed` the element itself is dropped but the children
123-
used
201+
extract (unwrap) the children of not allowed elements, by default, when
202+
`strong` is disallowed, it and it’s children are dropped, but with
203+
`unwrapDisallowed` the element itself is replaced by its children
124204
* `linkTarget` (`string` or `(href, children, title) => string`, optional)\
125-
Target to use on links (such as `_blank` for `<a target="_blank"…`)
205+
target to use on links (such as `_blank` for `<a target="_blank"…`)
126206
* `transformLinkUri` (`(href, children, title) => string`, default:
127-
[`./uri-transformer.js`][uri], optional)\
128-
URL to use for links.
129-
The default allows only `http`, `https`, `mailto`, and `tel`, and is
130-
exported from this module as `uriTransformer`.
131-
Pass `null` to allow all URLs.
132-
See [security][]
207+
[`uriTransformer`][uri-transformer], optional)\
208+
change URLs on links, pass `null` to allow all URLs, see [security][]
133209
* `transformImageUri` (`(src, alt, title) => string`, default:
134-
[`./uri-transformer.js`][uri], optional)\
135-
Same as `transformLinkUri` but for images
136-
* `components` (`Object.<string, Component>`, default: `{}`)\
137-
Object mapping tag names to React components
138-
* `remarkPlugins` (`Array.<Plugin>`, default: `[]`)\
139-
List of [remark plugins][remark-plugins] to use.
140-
See the next section for examples on how to pass options
141-
* `rehypePlugins` (`Array.<Plugin>`, default: `[]`)\
142-
List of [rehype plugins][rehype-plugins] to use.
143-
See the next section for examples on how to pass options
210+
[`uriTransformer`][uri-transformer], optional)\
211+
change URLs on images, pass `null` to allow all URLs, see [security][]
212+
213+
### `uriTransformer`
214+
215+
Our default URL transform, which you can overwrite (see props above).
216+
It’s given a URL and cleans it, by allowing only `http:`, `https:`, `mailto:`,
217+
and `tel:` URLs, absolute paths (`/example.png`), and hashes (`#some-place`).
218+
219+
See the [source code here][uri].
144220

145221
## Examples
146222

147223
### Use a plugin
148224

149225
This example shows how to use a remark plugin.
150-
In this case, [`remark-gfm`][gfm], which adds support for
151-
strikethrough, tables, tasklists and URLs directly:
226+
In this case, [`remark-gfm`][gfm], which adds support for strikethrough, tables,
227+
tasklists and URLs directly:
152228

153229
```jsx
154230
import React from 'react'
@@ -355,35 +431,74 @@ ReactDom.render(
355431

356432
</details>
357433

358-
## Architecture
434+
## Plugins
359435

360-
```txt
361-
react-markdown
362-
+-------------------------------------------------------------------------------------------------------------------------------------------+
363-
| |
364-
| +----------+ +----------------+ +---------------+ +----------------+ +------------+ |
365-
| | | | | | | | | | | |
366-
| -markdown->+ remark +-mdast->+ remark plugins +-mdast->+ remark-rehype +-hast->+ rehype plugins +-hast->+ components +-react elements-> |
367-
| | | | | | | | | | | |
368-
| +----------+ +----------------+ +---------------+ +----------------+ +------------+ |
369-
| |
370-
+-------------------------------------------------------------------------------------------------------------------------------------------+
371-
```
436+
We use [unified][], specifically [remark][] for markdown and [rehype][] for
437+
HTML, which are tools to transform content with plugins.
438+
Here are three good ways to find plugins:
439+
440+
* [`awesome-remark`][awesome-remark] and [`awesome-rehype`][awesome-rehype]
441+
— selection of the most awesome projects
442+
* [List of remark plugins][remark-plugins] and
443+
[list of rehype plugins][rehype-plugins]
444+
— list of all plugins
445+
* [`remark-plugin`][remark-plugin] and [`rehype-plugin`][rehype-plugin] topics
446+
— any tagged repo on GitHub
447+
448+
## Syntax
449+
450+
`react-markdown` follows CommonMark, which standardizes the differences between
451+
markdown implementations, by default.
452+
Some syntax extensions are supported through plugins.
453+
454+
We use [`micromark`][micromark] under the hood for our parsing.
455+
See its documentation for more information on markdown, CommonMark, and
456+
extensions.
372457

373-
relevant links: [markdown](https://commonmark.org), [remark](https://github.com/remarkjs/remark), [mdast](https://github.com/syntax-tree/mdast), [remark plugins](https://github.com/remarkjs/remark/blob/main/doc/plugins.md), [remark-rehype](https://github.com/remarkjs/remark-rehype), [hast](https://github.com/syntax-tree/hast), [rehype plugins](https://github.com/rehypejs/rehype/blob/main/doc/plugins.md), [components](#appendix-b-components)
458+
## Types
374459

375-
To understand what this project does, it’s very important to first understand
376-
what unified does: please read through the [`unifiedjs/unified`](https://github.com/unifiedjs/unified)
377-
readme (the part until you hit the API section is required reading).
460+
This package is fully typed with [TypeScript][].
461+
It exports `Options` and `Components` types, which specify the interface of the
462+
accepted props and components.
378463

379-
react-markdown is a unified pipeline — wrapped so that most folks don’t need to
380-
directly interact with unified. The processor goes through these steps:
464+
## Compatibility
381465

382-
* Parse Markdown to mdast (markdown syntax tree)
383-
* Transform through remark (markdown ecosystem)
384-
* Transform mdast to hast (HTML syntax tree)
385-
* Transform through rehype (HTML ecosystem)
386-
* Render hast to react with components
466+
Projects maintained by the unified collective are compatible with all maintained
467+
versions of Node.js.
468+
As of now, that is Node.js 12.20+, 14.14+, and 16.0+.
469+
Our projects sometimes work with older versions, but this is not guaranteed.
470+
They work in all modern browsers (essentially: everything not IE 11).
471+
You can use a bundler (such as esbuild, webpack, or Rollup) to use this package
472+
in your project, and use its options (or plugins) to add support for legacy
473+
browsers.
474+
475+
## Architecture
476+
477+
<pre><code> react-markdown
478+
+----------------------------------------------------------------------------------------------------------------+
479+
| |
480+
| +----------+ +----------------+ +---------------+ +----------------+ +------------+ |
481+
| | | | | | | | | | | |
482+
<a href="https://commonmark.org">markdown</a>-+->+ <a href="https://github.com/remarkjs/remark">remark</a> +-<a href="https://github.com/syntax-tree/mdast">mdast</a>->+ <a href="https://github.com/remarkjs/remark/blob/main/doc/plugins.md">remark plugins</a> +-<a href="https://github.com/syntax-tree/mdast">mdast</a>->+ <a href="https://github.com/remarkjs/remark-rehype">remark-rehype</a> +-<a href="https://github.com/syntax-tree/hast">hast</a>->+ <a href="https://github.com/rehypejs/rehype/blob/main/doc/plugins.md">rehype plugins</a> +-<a href="https://github.com/syntax-tree/hast">hast</a>->+ <a href="#appendix-b-components">components</a> +-+->react elements
483+
| | | | | | | | | | | |
484+
| +----------+ +----------------+ +---------------+ +----------------+ +------------+ |
485+
| |
486+
+----------------------------------------------------------------------------------------------------------------+
487+
</code></pre>
488+
489+
To understand what this project does, it’s important to first understand what
490+
unified does: please read through the [`unifiedjs/unified`][unified] readme (the
491+
part until you hit the API section is required reading).
492+
493+
`react-markdown` is a unified pipeline — wrapped so that most folks don’t need
494+
to directly interact with unified.
495+
The processor goes through these steps:
496+
497+
* parse markdown to mdast (markdown syntax tree)
498+
* transform through remark (markdown ecosystem)
499+
* transform mdast to hast (HTML syntax tree)
500+
* transform through rehype (HTML ecosystem)
501+
* render hast to React with components
387502

388503
## Appendix A: HTML in markdown
389504

@@ -432,7 +547,7 @@ markdown!
432547

433548
You can also change the things that come from markdown:
434549

435-
```js
550+
```jsx
436551
<ReactMarkdown
437552
components={{
438553
// Map `h1` (`# heading`) to use `h2`s.
@@ -444,9 +559,8 @@ You can also change the things that come from markdown:
444559
```
445560

446561
The keys in components are HTML equivalents for the things you write with
447-
markdown (such as `h1` for `# heading`)****
448-
449-
**** Normally, in markdown, those are: `a`, `blockquote`, `code`, `em`, `h1`,
562+
markdown (such as `h1` for `# heading`).
563+
Normally, in markdown, those are: `a`, `blockquote`, `br`, `code`, `em`, `h1`,
450564
`h2`, `h3`, `h4`, `h5`, `h6`, `hr`, `img`, `li`, `ol`, `p`, `pre`, `strong`, and
451565
`ul`.
452566
With [`remark-gfm`][gfm], you can also use: `del`, `input`, `table`, `tbody`,
@@ -464,7 +578,7 @@ There are some extra props passed.
464578
* `className` (`string?`)
465579
— set to `language-js` or so when using ` ```js `
466580
* `h1`, `h2`, `h3`, `h4`, `h5`, `h6`
467-
* `level` (`number` beween 1 and 6)
581+
* `level` (`number` between 1 and 6)
468582
— heading rank
469583
* `input` (when using [`remark-gfm`][gfm])
470584
* `checked` (`boolean`)
@@ -523,19 +637,23 @@ Optionally, components will also receive:
523637
Use of `react-markdown` is secure by default.
524638
Overwriting `transformLinkUri` or `transformImageUri` to something insecure will
525639
open you up to XSS vectors.
526-
Furthermore, the `remarkPlugins` and `rehypePlugins` you use and `components`
527-
you write may be insecure.
640+
Furthermore, the `remarkPlugins`, `rehypePlugins`, and `components` you use may
641+
be insecure.
528642

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

533647
## Related
534648

535649
* [`MDX`](https://github.com/mdx-js/mdx)
536650
— JSX *in* markdown
537651
* [`remark-gfm`](https://github.com/remarkjs/remark-gfm)
538-
— Plugin for GitHub flavored markdown support
652+
— add support for GitHub flavored markdown support
653+
* [`react-remark`][react-remark]
654+
— modern hook based alternative
655+
* [`rehype-react`][rehype-react]
656+
— turn HTML into React elements
539657

540658
## Contribute
541659

@@ -579,6 +697,8 @@ abide by its terms.
579697

580698
[npm]: https://docs.npmjs.com/cli/install
581699

700+
[skypack]: https://www.skypack.dev
701+
582702
[health]: https://github.com/remarkjs/.github
583703

584704
[contributing]: https://github.com/remarkjs/.github/blob/HEAD/contributing.md
@@ -591,12 +711,12 @@ abide by its terms.
591711

592712
[author]: https://espen.codes/
593713

714+
[micromark]: https://github.com/micromark/micromark
715+
594716
[remark]: https://github.com/remarkjs/remark
595717

596718
[demo]: https://remarkjs.github.io/react-markdown/
597719

598-
[learn]: https://commonmark.org/help/
599-
600720
[position]: https://github.com/syntax-tree/unist#position
601721

602722
[gfm]: https://github.com/remarkjs/remark-gfm
@@ -613,12 +733,46 @@ abide by its terms.
613733

614734
[rehype-plugins]: https://github.com/rehypejs/rehype/blob/main/doc/plugins.md#list-of-plugins
615735

616-
[cm-html]: https://spec.commonmark.org/0.29/#html-blocks
736+
[awesome-remark]: https://github.com/remarkjs/awesome-remark
737+
738+
[awesome-rehype]: https://github.com/rehypejs/awesome-rehype
739+
740+
[remark-plugin]: https://github.com/topics/remark-plugin
741+
742+
[rehype-plugin]: https://github.com/topics/rehype-plugin
743+
744+
[cm-html]: https://spec.commonmark.org/0.30/#html-blocks
617745

618746
[uri]: https://github.com/remarkjs/react-markdown/blob/main/lib/uri-transformer.js
619747

748+
[uri-transformer]: #uritransformer
749+
750+
[react]: http://reactjs.org
751+
752+
[cheat]: https://commonmark.org/help/
753+
754+
[unified]: https://github.com/unifiedjs/unified
755+
756+
[rehype]: https://github.com/rehypejs/rehype
757+
758+
[react-remark]: https://github.com/remarkjs/react-remark
759+
760+
[rehype-react]: https://github.com/rehypejs/rehype-react
761+
762+
[mdx]: https://github.com/mdx-js/mdx/
763+
764+
[typescript]: https://www.typescriptlang.org
765+
620766
[security]: #security
621767

768+
[components]: #appendix-b-components
769+
770+
[plugins]: #plugins
771+
772+
[syntax]: #syntax
773+
622774
[react-syntax-highlighter]: https://github.com/react-syntax-highlighter/react-syntax-highlighter
623775

624776
[conor]: https://github.com/conorhastings
777+
778+
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c

0 commit comments

Comments
 (0)
Please sign in to comment.