1
+ <!--
2
+ Notes for maintaining this document:
3
+
4
+ * Update the link for `cm-html` once in a while
5
+ -->
6
+
1
7
# react-markdown
2
8
3
9
[ ![ Build] [ build-badge ]] [ build ]
8
14
[ ![ Backers] [ backers-badge ]] [ collective ]
9
15
[ ![ Chat] [ chat-badge ]] [ chat ]
10
16
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).
12
75
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.
14
79
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] [ ] .
16
86
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
19
88
20
- [ npm] [ ] :
89
+ This package is [ ESM only] [ esm ] .
90
+ In Node.js (version 12.20+, 14.14+, or 16.0+), install with [ npm] [ ] :
21
91
22
92
``` sh
23
93
npm install react-markdown
24
94
```
25
95
26
- ## Why this one?
96
+ In Deno with [ Skypack ] [ ] :
27
97
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
+ ```
35
109
36
110
## Use
37
111
@@ -87,68 +161,70 @@ ReactDom.render(
87
161
88
162
## API
89
163
90
- This package exports the following identifier: ` uriTransformer ` .
164
+ This package exports the following identifier:
165
+ [ ` uriTransformer ` ] [ uri-transformer ] .
91
166
The default export is ` ReactMarkdown ` .
92
167
93
168
### ` props `
94
169
95
170
* ` 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
97
178
* ` className ` (` string? ` )\
98
- Wrap the markdown in a ` div ` with this class name
179
+ wrap the markdown in a ` div ` with this class name
99
180
* ` skipHtml ` (` boolean ` , default: ` false ` )\
100
- Ignore HTML in Markdown completely
181
+ ignore HTML in markdown completely
101
182
* ` 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
103
184
(` data-sourcepos="3:1-3:13" ` )
104
185
* ` rawSourcePos ` (` boolean ` , default: ` false ` )\
105
- Pass a prop to all components with their [ position] [ ]
186
+ pass a prop to all components with their [ position] [ ]
106
187
(` sourcePosition: {start: {line: 3, column: 1}, end:…} ` )
107
188
* ` 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
109
190
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
116
197
* ` 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!
119
200
* ` 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
124
204
* ` 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"… ` )
126
206
* ` 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] [ ]
133
209
* ` 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 ] .
144
220
145
221
## Examples
146
222
147
223
### Use a plugin
148
224
149
225
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:
152
228
153
229
``` jsx
154
230
import React from ' react'
@@ -355,35 +431,74 @@ ReactDom.render(
355
431
356
432
</details >
357
433
358
- ## Architecture
434
+ ## Plugins
359
435
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.
372
457
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
374
459
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 .
378
463
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
381
465
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
387
502
388
503
## Appendix A: HTML in markdown
389
504
@@ -432,7 +547,7 @@ markdown!
432
547
433
548
You can also change the things that come from markdown:
434
549
435
- ``` js
550
+ ``` jsx
436
551
< ReactMarkdown
437
552
components= {{
438
553
// Map `h1` (`# heading`) to use `h2`s.
@@ -444,9 +559,8 @@ You can also change the things that come from markdown:
444
559
```
445
560
446
561
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 ` ,
450
564
` h2 ` , ` h3 ` , ` h4 ` , ` h5 ` , ` h6 ` , ` hr ` , ` img ` , ` li ` , ` ol ` , ` p ` , ` pre ` , ` strong ` , and
451
565
` ul ` .
452
566
With [ ` remark-gfm ` ] [ gfm ] , you can also use: ` del ` , ` input ` , ` table ` , ` tbody ` ,
@@ -464,7 +578,7 @@ There are some extra props passed.
464
578
* ` className ` (` string? ` )
465
579
— set to ` language-js ` or so when using ` ```js `
466
580
* ` h1 ` , ` h2 ` , ` h3 ` , ` h4 ` , ` h5 ` , ` h6 `
467
- * ` level ` (` number ` beween 1 and 6)
581
+ * ` level ` (` number ` between 1 and 6)
468
582
— heading rank
469
583
* ` input ` (when using [ ` remark-gfm ` ] [ gfm ] )
470
584
* ` checked ` (` boolean ` )
@@ -523,19 +637,23 @@ Optionally, components will also receive:
523
637
Use of ` react-markdown ` is secure by default.
524
638
Overwriting ` transformLinkUri ` or ` transformImageUri ` to something insecure will
525
639
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.
528
642
529
643
To make sure the content is completely safe, even after what plugins do,
530
644
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.
532
646
533
647
## Related
534
648
535
649
* [ ` MDX ` ] ( https://github.com/mdx-js/mdx )
536
650
— JSX * in* markdown
537
651
* [ ` 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
539
657
540
658
## Contribute
541
659
@@ -579,6 +697,8 @@ abide by its terms.
579
697
580
698
[ npm ] : https://docs.npmjs.com/cli/install
581
699
700
+ [ skypack ] : https://www.skypack.dev
701
+
582
702
[ health ] : https://github.com/remarkjs/.github
583
703
584
704
[ contributing ] : https://github.com/remarkjs/.github/blob/HEAD/contributing.md
@@ -591,12 +711,12 @@ abide by its terms.
591
711
592
712
[ author ] : https://espen.codes/
593
713
714
+ [ micromark ] : https://github.com/micromark/micromark
715
+
594
716
[ remark ] : https://github.com/remarkjs/remark
595
717
596
718
[ demo ] : https://remarkjs.github.io/react-markdown/
597
719
598
- [ learn ] : https://commonmark.org/help/
599
-
600
720
[ position ] : https://github.com/syntax-tree/unist#position
601
721
602
722
[ gfm ] : https://github.com/remarkjs/remark-gfm
@@ -613,12 +733,46 @@ abide by its terms.
613
733
614
734
[ rehype-plugins ] : https://github.com/rehypejs/rehype/blob/main/doc/plugins.md#list-of-plugins
615
735
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
617
745
618
746
[ uri ] : https://github.com/remarkjs/react-markdown/blob/main/lib/uri-transformer.js
619
747
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
+
620
766
[ security ] : #security
621
767
768
+ [ components ] : #appendix-b-components
769
+
770
+ [ plugins ] : #plugins
771
+
772
+ [ syntax ] : #syntax
773
+
622
774
[ react-syntax-highlighter ] : https://github.com/react-syntax-highlighter/react-syntax-highlighter
623
775
624
776
[ conor ] : https://github.com/conorhastings
777
+
778
+ [ esm ] : https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
0 commit comments