markdown-to-jsx 9.0.0-rc.1 → 9.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,25 +9,30 @@ Some special features of the library:
9
9
 
10
10
  - Any HTML tags rendered by the compiler and/or `<Markdown>` component can be overridden to include additional props or even a different HTML representation entirely.
11
11
 
12
- - All GFM special syntaxes are supported, including tables, task lists, strikethrough, autolinks, and more.
12
+ - All GFM special syntaxes are supported, including tables, task lists, strikethrough, autolinks, tag filtering, and more.
13
13
 
14
14
  - Fenced code blocks with [highlight.js](https://highlightjs.org/) support; see [Syntax highlighting](#syntax-highlighting) for instructions on setting up highlight.js.
15
15
 
16
- ## Table of Contents
16
+ <h2>Table of Contents</h2>
17
17
 
18
18
  <!-- TOC -->
19
19
 
20
- - [Table of Contents](#table-of-contents)
21
20
  - [Upgrading](#upgrading)
22
21
  - [From v8.x to v9.x](#from-v8x-to-v9x)
23
22
  - [From v7.x to v8.x](#from-v7x-to-v8x)
24
23
  - [Installation](#installation)
25
24
  - [Usage](#usage)
26
- - [Parsing Options](#parsing-options)
25
+ - [Entry Points](#entry-points)
26
+ - [Main](#main)
27
+ - [React](#react)
28
+ - [HTML](#html)
29
+ - [Markdown](#markdown)
30
+ - [Library Options](#library-options)
27
31
  - [options.forceBlock](#optionsforceblock)
28
32
  - [options.forceInline](#optionsforceinline)
29
33
  - [options.wrapper](#optionswrapper)
30
34
  - [Other useful recipes](#other-useful-recipes)
35
+ - [options.wrapperProps](#optionswrapperprops)
31
36
  - [options.forceWrapper](#optionsforcewrapper)
32
37
  - [options.overrides - Void particular banned tags](#optionsoverrides---void-particular-banned-tags)
33
38
  - [options.overrides - Override Any HTML Tag's Representation](#optionsoverrides---override-any-html-tags-representation)
@@ -38,25 +43,21 @@ Some special features of the library:
38
43
  - [options.sanitizer](#optionssanitizer)
39
44
  - [options.slugify](#optionsslugify)
40
45
  - [options.disableAutoLink](#optionsdisableautolink)
46
+ - [options.preserveFrontmatter](#optionspreservefrontmatter)
41
47
  - [options.disableParsingRawHTML](#optionsdisableparsingrawhtml)
48
+ - [options.tagfilter](#optionstagfilter)
42
49
  - [Syntax highlighting](#syntax-highlighting)
43
50
  - [Handling shortcodes](#handling-shortcodes)
44
51
  - [Getting the smallest possible bundle size](#getting-the-smallest-possible-bundle-size)
45
52
  - [Usage with Preact](#usage-with-preact)
46
- - [Gotchas](#gotchas)
47
- - [Passing props to stringified React components](#passing-props-to-stringified-react-components)
48
- - [Significant indentation inside arbitrary HTML](#significant-indentation-inside-arbitrary-html)
53
+ - [AST Anatomy](#ast-anatomy)
54
+ - [Node Types](#node-types)
55
+ - [Example AST Structure](#example-ast-structure)
56
+ - [Type Checking](#type-checking)
57
+ - [Gotchas](#gotchas)
58
+ - [Passing props to stringified React components](#passing-props-to-stringified-react-components)
59
+ - [Significant indentation inside arbitrary HTML](#significant-indentation-inside-arbitrary-html)
49
60
  - [Code blocks](#code-blocks)
50
- - [Entry Points](#entry-points)
51
- - [Main](#main)
52
- - [React](#react)
53
- - [HTML](#html)
54
- - [Markdown](#markdown)
55
- - [Using The Parser Low-Level AST API](#using-the-parser-low-level-ast-api)
56
- - [AST Anatomy](#ast-anatomy)
57
- - [Node Types](#node-types)
58
- - [Example AST Structure](#example-ast-structure)
59
- - [Type Checking](#type-checking)
60
61
  - [Changelog](#changelog)
61
62
  - [Donate](#donate)
62
63
 
@@ -92,6 +93,19 @@ import { compiler } from 'markdown-to-jsx'
92
93
  compiler('&le; symbol') // All entities supported automatically
93
94
  ```
94
95
 
96
+ - **`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.
97
+
98
+ ```typescript
99
+ // Before (v8) - tags rendered as JSX elements
100
+ compiler('<script>alert("xss")</script>') // Rendered as <script> element
101
+
102
+ // After (v9) - tags escaped by default
103
+ compiler('<script>alert("xss")</script>') // Renders as <span>&lt;script&gt;</span>
104
+
105
+ // To restore old behavior:
106
+ compiler('<script>alert("xss")</script>', { tagfilter: false })
107
+ ```
108
+
95
109
  **New Features:**
96
110
 
97
111
  - **New `parser` function**: Provides direct access to the parsed AST without rendering. This is the recommended way to get AST nodes.
@@ -204,7 +218,75 @@ render(<Markdown># Hello world!</Markdown>, document.body)
204
218
 
205
219
  \* **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).**
206
220
 
207
- ### Parsing Options
221
+ ### Entry Points
222
+
223
+ `markdown-to-jsx` provides multiple entry points for different use cases:
224
+
225
+ #### Main
226
+
227
+ The legacy\*default entry point exports everything, including the React compiler and component:
228
+
229
+ ```tsx
230
+ import Markdown, { compiler, parser } from 'markdown-to-jsx'
231
+ ```
232
+
233
+ _The React code in this entry point is deprecated and will be removed in a future major release, migrate to `markdown-to-jsx/react`._
234
+
235
+ #### React
236
+
237
+ For React-specific usage, import from the `/react` entry point:
238
+
239
+ ```tsx
240
+ import Markdown, { compiler, parser, astToJSX } from 'markdown-to-jsx/react'
241
+
242
+ // Use compiler for markdown → JSX
243
+ const jsxElement = compiler('# Hello world')
244
+
245
+ const markdown = `# Hello world`
246
+
247
+ function App() {
248
+ return <Markdown children={markdown} />
249
+ }
250
+
251
+ // Or use parser + astToJSX for total control
252
+ const ast = parser('# Hello world')
253
+ const jsxElement2 = astToJSX(ast)
254
+ ```
255
+
256
+ #### HTML
257
+
258
+ For HTML string output (server-side rendering), import from the `/html` entry point:
259
+
260
+ ```tsx
261
+ import { compiler, html, parser } from 'markdown-to-jsx/html'
262
+
263
+ // Convenience function that combines parsing and HTML rendering
264
+ const htmlString = compiler('# Hello world')
265
+ // Returns: '<h1>Hello world</h1>'
266
+
267
+ // Or use parser + html separately for more control
268
+ const ast = parser('# Hello world')
269
+ const htmlString2 = html(ast)
270
+ ```
271
+
272
+ #### Markdown
273
+
274
+ For markdown-to-markdown compilation (normalization and formatting), import from the `/markdown` entry point:
275
+
276
+ ```typescript
277
+ import { compiler, astToMarkdown, parser } from 'markdown-to-jsx/markdown'
278
+
279
+ // Convenience function that parses and recompiles markdown
280
+ const normalizedMarkdown = compiler('# Hello world\n\nExtra spaces!')
281
+ // Returns: '# Hello world\n\nExtra spaces!\n'
282
+
283
+ // Or work with AST directly
284
+ const ast = parser('# Hello world')
285
+ const normalizedMarkdown2 = astToMarkdown(ast)
286
+ // Returns: '# Hello world\n'
287
+ ```
288
+
289
+ ### Library Options
208
290
 
209
291
  #### options.forceBlock
210
292
 
@@ -283,6 +365,24 @@ compiler('One\n\nTwo\n\nThree', { wrapper: null })
283
365
 
284
366
  To render children at the same DOM level as `<Markdown>` with no HTML wrapper, set `wrapper` to `React.Fragment`. This will still wrap your children in a React node for the purposes of rendering, but the wrapper element won't show up in the DOM.
285
367
 
368
+ #### options.wrapperProps
369
+
370
+ Props to apply to the wrapper element when `wrapper` is used.
371
+
372
+ ```tsx
373
+ <Markdown options={{
374
+ wrapper: 'article',
375
+ wrapperProps: { className: 'post', 'data-testid': 'markdown-content' }
376
+ }}>
377
+ # Hello World
378
+ </Markdown>
379
+
380
+ // renders
381
+ <article class="post" data-testid="markdown-content">
382
+ <h1>Hello World</h1>
383
+ </article>
384
+ ```
385
+
286
386
  #### options.forceWrapper
287
387
 
288
388
  By default, the compiler does not wrap the rendered contents if there is only a single child. You can change this by setting `forceWrapper` to `true`. If the child is inline, it will not necessarily be wrapped in a `span`.
@@ -300,7 +400,15 @@ By default, the compiler does not wrap the rendered contents if there is only a
300
400
 
301
401
  #### options.overrides - Void particular banned tags
302
402
 
303
- Pass the `options.overrides` prop to the compiler or `<Markdown>` component with an implementation that return `null` for tags you wish to exclude from the rendered output. It is recommended to void `script`, `iframe`, `object`, and `style` tags to avoid XSS attacks when working with user-generated content. For example, to void the `iframe` tag:
403
+ Pass the `options.overrides` prop to the compiler or `<Markdown>` component with an implementation that return `null` for tags you wish to exclude from the rendered output. This provides complete removal of tags from the output.
404
+
405
+ **Note**: The `tagfilter` option provides default escaping of dangerous tags (`script`, `iframe`, `style`, `title`, `textarea`, `xmp`, `noembed`, `noframes`, `plaintext`). Use `overrides` when you need to:
406
+
407
+ - Remove additional tags not covered by `tagfilter` (like `object`)
408
+ - Have more control over tag removal vs. escaping
409
+ - Disable `tagfilter` but still want to remove specific tags
410
+
411
+ For example, to void the `iframe` tag:
304
412
 
305
413
  ```tsx
306
414
  import Markdown from 'markdown-to-jsx'
@@ -317,7 +425,7 @@ render(
317
425
  // renders: ""
318
426
  ```
319
427
 
320
- The library does not void any tags by default to avoid surprising behavior for personal use cases.
428
+ The library does not void any tags by default (except through `tagfilter` escaping), allowing you to choose the appropriate security approach for your use case.
321
429
 
322
430
  #### options.overrides - Override Any HTML Tag's Representation
323
431
 
@@ -638,6 +746,61 @@ compiler(
638
746
  </span>
639
747
  ```
640
748
 
749
+ #### options.preserveFrontmatter
750
+
751
+ By default, YAML frontmatter at the beginning of markdown documents is parsed but not rendered in the output. Set this option to `true` to include the frontmatter in the rendered output. For HTML/JSX output, frontmatter is rendered as a `<pre>` element. For markdown-to-markdown compilation, frontmatter is included in the output markdown.
752
+
753
+ | Compiler Type | Default Behavior | When `preserveFrontmatter: true` | When `preserveFrontmatter: false` |
754
+ | ------------------------ | --------------------------- | -------------------------------- | --------------------------------- |
755
+ | **React/HTML** | ❌ Don't render frontmatter | ✅ Render as `<pre>` element | ❌ Don't render frontmatter |
756
+ | **Markdown-to-Markdown** | ✅ Preserve frontmatter | ✅ Preserve frontmatter | ❌ Exclude frontmatter |
757
+
758
+ ```tsx
759
+ <Markdown options={{ preserveFrontmatter: true }}>
760
+ {`---
761
+ title: My Document
762
+ author: John Doe
763
+ ---
764
+
765
+ # Content
766
+
767
+ This is the main content.`
768
+ }
769
+ </Markdown>
770
+
771
+ // renders:
772
+
773
+ <div>
774
+ <pre>---
775
+ title: My Document
776
+ author: John Doe
777
+ ---</pre>
778
+ <h1>Content</h1>
779
+ <p>This is the main content.</p>
780
+ </div>
781
+ ```
782
+
783
+ For markdown-to-markdown compilation:
784
+
785
+ ```tsx
786
+ import { compiler } from 'markdown-to-jsx/markdown'
787
+
788
+ const markdown = `---
789
+ title: My Document
790
+ author: John Doe
791
+ ---
792
+
793
+ # Content`
794
+
795
+ // With preserveFrontmatter: true (default)
796
+ compiler(markdown, { preserveFrontmatter: true })
797
+ // returns: "---\ntitle: My Document\nauthor: John Doe\n---\n\n# Content"
798
+
799
+ // With preserveFrontmatter: false
800
+ compiler(markdown, { preserveFrontmatter: false })
801
+ // returns: "# Content"
802
+ ```
803
+
641
804
  #### options.disableParsingRawHTML
642
805
 
643
806
  By default, raw HTML is parsed to JSX. This behavior can be disabled if desired.
@@ -656,6 +819,27 @@ compiler('This text has <span>html</span> in it but it won't be rendered', { dis
656
819
  <span>This text has &lt;span&gt;html&lt;/span&gt; in it but it won't be rendered</span>
657
820
  ```
658
821
 
822
+ #### options.tagfilter
823
+
824
+ By default, dangerous HTML tags are filtered and escaped to prevent XSS attacks. This applies to both HTML string output and React JSX output. The following tags are filtered: `script`, `iframe`, `style`, `title`, `textarea`, `xmp`, `noembed`, `noframes`, `plaintext`.
825
+
826
+ ```tsx
827
+ // Tags are escaped by default (GFM-compliant)
828
+ compiler('<script>alert("xss")</script>')
829
+ // HTML output: '<span>&lt;script&gt;</span>'
830
+ // React output: <span>&lt;script&gt;</span>
831
+
832
+ // Disable tag filtering:
833
+ compiler('<script>alert("xss")</script>', { tagfilter: false })
834
+ // HTML output: '<script></script>'
835
+ // React output: <script></script>
836
+ ```
837
+
838
+ **Note**: Even when `tagfilter` is disabled, other security measures remain active:
839
+
840
+ - URL sanitization preventing `javascript:` and `vbscript:` schemes in `href` and `src` attributes
841
+ - Protection against `data:` URLs (except safe `data:image/*` MIME types)
842
+
659
843
  ### Syntax highlighting
660
844
 
661
845
  When using [fenced code blocks](https://www.markdownguide.org/extended-syntax/#syntax-highlighting) with language annotation, that language will be added to the `<code>` element as `class="lang-${language}"`. For best results, you can use `options.overrides` to provide an appropriate syntax highlighting integration like this one using `highlight.js`:
@@ -771,198 +955,13 @@ Here are instructions for some of the popular bundlers:
771
955
 
772
956
  Everything will work just fine! Simply [Alias `react` to `preact/compat`](https://preactjs.com/guide/v10/switching-to-preact#setting-up-compat) like you probably already are doing.
773
957
 
774
- ## Gotchas
775
-
776
- ### Passing props to stringified React components
777
-
778
- Using the [`options.overrides`](#optionsoverrides---rendering-arbitrary-react-components) functionality to render React components, props are passed into the component in stringifed form. It is up to you to parse the string to make use of the data.
779
-
780
- ```tsx
781
- const Table: React.FC<
782
- JSX.IntrinsicElements['table'] & {
783
- columns: string
784
- dataSource: string
785
- }
786
- > = ({ columns, dataSource, ...props }) => {
787
- const parsedColumns = JSON.parse(columns)
788
- const parsedData = JSON.parse(dataSource)
789
-
790
- return (
791
- <div {...props}>
792
- <h1>Columns</h1>
793
- {parsedColumns.map(column => (
794
- <span key={column.key}>{column.title}</span>
795
- ))}
796
-
797
- <h2>Data</h2>
798
- {parsedData.map(datum => (
799
- <span key={datum.key}>{datum.Month}</span>
800
- ))}
801
- </div>
802
- )
803
- }
804
-
805
- /**
806
- * Example HTML in markdown:
807
- *
808
- * <Table
809
- * columns={[{ title: 'Month', dataIndex: 'Month', key: 'Month' }]}
810
- * dataSource={[
811
- * {
812
- * Month: '2024-09-01',
813
- * 'Forecasted Revenue': '$3,137,678.85',
814
- * 'Forecasted Expenses': '$2,036,660.28',
815
- * key: 0,
816
- * },
817
- * ]}
818
- * />
819
- */
820
- ```
821
-
822
- ### Significant indentation inside arbitrary HTML
823
-
824
- People usually write HTML like this:
825
-
826
- ```html
827
- <div>Hey, how are you?</div>
828
- ```
829
-
830
- Note the leading spaces before the inner content. This sort of thing unfortunately clashes with existing markdown syntaxes since 4 spaces === a code block and other similar collisions.
831
-
832
- To get around this, `markdown-to-jsx` left-trims approximately as much whitespace as the first line inside the HTML block. So for example:
833
-
834
- ```html
835
- <div># Hello How are you?</div>
836
- ```
837
-
838
- The two leading spaces in front of "# Hello" would be left-trimmed from all lines inside the HTML block. In the event that there are varying amounts of indentation, only the amount of the first line is trimmed.
839
-
840
- > NOTE! These syntaxes work just fine when you aren't writing arbitrary HTML wrappers inside your markdown. This is very much an edge case of an edge case. 🙃
841
-
842
- #### Code blocks
843
-
844
- ⛔️
845
-
846
- ```md
847
- <div>
848
- var some = code();
849
- </div>
850
- ```
851
-
852
-
853
-
854
- ````md
855
- <div>
856
- ```js
857
- var some = code();
858
- ```
859
- </div>
860
- ````
861
-
862
- ## Entry Points
863
-
864
- `markdown-to-jsx` provides multiple entry points for different use cases:
865
-
866
- ### Main
867
-
868
- The legacy\*default entry point exports everything, including the React compiler and component:
869
-
870
- ```tsx
871
- import Markdown, { compiler, parser } from 'markdown-to-jsx'
872
- ```
873
-
874
- _The React code in this entry point is deprecated and will be removed in a future major release, migrate to `markdown-to-jsx/react`._
875
-
876
- ### React
877
-
878
- For React-specific usage, import from the `/react` entry point:
879
-
880
- ```tsx
881
- import Markdown, { compiler, parser, astToJSX } from 'markdown-to-jsx/react'
882
-
883
- // Use compiler for markdown → JSX
884
- const jsxElement = compiler('# Hello world')
885
-
886
- const markdown = `# Hello world`
887
-
888
- function App() {
889
- return <Markdown children={markdown} />
890
- }
891
-
892
- // Or use parser + astToJSX for total control
893
- const ast = parser('# Hello world')
894
- const jsxElement2 = astToJSX(ast)
895
- ```
896
-
897
- ### HTML
898
-
899
- For HTML string output (server-side rendering), import from the `/html` entry point:
900
-
901
- ```tsx
902
- import { compiler, html, parser } from 'markdown-to-jsx/html'
903
-
904
- // Convenience function that combines parsing and HTML rendering
905
- const htmlString = compiler('# Hello world')
906
- // Returns: '<h1>Hello world</h1>'
907
-
908
- // Or use parser + html separately for more control
909
- const ast = parser('# Hello world')
910
- const htmlString2 = html(ast)
911
- ```
912
-
913
- ### Markdown
914
-
915
- For markdown-to-markdown compilation (normalization and formatting), import from the `/markdown` entry point:
916
-
917
- ```typescript
918
- import { compiler, astToMarkdown, parser } from 'markdown-to-jsx/markdown'
919
-
920
- // Convenience function that parses and recompiles markdown
921
- const normalizedMarkdown = compiler('# Hello world\n\nExtra spaces!')
922
- // Returns: '# Hello world\n\nExtra spaces!\n'
923
-
924
- // Or work with AST directly
925
- const ast = parser('# Hello world')
926
- const normalizedMarkdown2 = astToMarkdown(ast)
927
- // Returns: '# Hello world\n'
928
- ```
929
-
930
- ## Using The Parser (Low-Level AST API)
931
-
932
- The `parser` function provides direct access to the parsed AST without rendering:
933
-
934
- ```tsx
935
- import { parser } from 'markdown-to-jsx'
936
- import type { MarkdownToJSX } from 'markdown-to-jsx'
937
-
938
- // Parse markdown to AST
939
- const ast = parser('# Hello world')
940
-
941
- // TypeScript: AST is MarkdownToJSX.ASTNode[]
942
- console.log(ast) // Array of parsed nodes
943
-
944
- // You can then render with html() or compiler()
945
- ```
946
-
947
- The `parser` function accepts:
948
-
949
- - `source: string` - markdown source
950
- - `state?: MarkdownToJSX.State` - parsing state (defaults: `{ inline: false, refs: {} }`)
951
- - `options?: MarkdownToJSX.Options` - parsing options
952
-
953
- Use `parser` when you need:
954
-
955
- - Direct AST access without React rendering
956
- - Custom rendering logic
957
- - AST manipulation before rendering
958
-
959
- ## AST Anatomy
958
+ ### AST Anatomy
960
959
 
961
960
  The Abstract Syntax Tree (AST) is a structured representation of parsed markdown. Each node in the AST has a `type` property that identifies its kind, and type-specific properties.
962
961
 
963
962
  **Important:** The first node in the AST is typically a `RuleType.refCollection` node that contains all reference definitions found in the document, including footnotes (stored with keys prefixed with `^`). This node is skipped during rendering but is useful for accessing reference data. Footnotes are automatically extracted from the refCollection and rendered in a `<footer>` element by both `compiler()` and `astToJSX()`.
964
963
 
965
- ### Node Types
964
+ #### Node Types
966
965
 
967
966
  The AST consists of the following node types (use `RuleType` to check node types):
968
967
 
@@ -987,7 +986,7 @@ The AST consists of the following node types (use `RuleType` to check node types
987
986
  - `RuleType.orderedList` / `RuleType.unorderedList` - Lists
988
987
  ```tsx
989
988
  { type: RuleType.orderedList, items: [[...]], start?: 1 }
990
- { type: RuleType.unorderedList, items: [[...]], ordered: false }
989
+ { type: RuleType.unorderedList, items: [[...]] }
991
990
  ```
992
991
  - `RuleType.table` - Tables
993
992
  ```tsx
@@ -1020,21 +1019,30 @@ The AST consists of the following node types (use `RuleType` to check node types
1020
1019
  ```tsx
1021
1020
  { type: RuleType.image, target: "image.png", alt: "description" }
1022
1021
  ```
1023
- - `RuleType.refLink` / `RuleType.refImage` - Reference-style links/images
1024
- ```tsx
1025
- { type: RuleType.refLink, ref: "linkref", children: [...] }
1026
- ```
1027
1022
 
1028
1023
  **Other nodes:**
1029
1024
 
1030
1025
  - `RuleType.breakLine` - Hard line breaks (` `)
1031
1026
  - `RuleType.breakThematic` - Horizontal rules (`---`)
1032
1027
  - `RuleType.gfmTask` - GFM task list items (`- [ ]`)
1028
+ - `RuleType.ref` - Reference definition node (not rendered, stored in refCollection)
1033
1029
  - `RuleType.refCollection` - Reference definitions collection (appears at AST root, includes footnotes with `^` prefix)
1034
1030
  - `RuleType.footnote` - Footnote definition node (not rendered, stored in refCollection)
1035
1031
  - `RuleType.footnoteReference` - Footnote reference (`[^identifier]`)
1032
+ - `RuleType.frontmatter` - YAML frontmatter blocks
1033
+ ```tsx
1034
+ { type: RuleType.frontmatter, text: "---\ntitle: My Title\n---" }
1035
+ ```
1036
+ - `RuleType.htmlComment` - HTML comment nodes
1037
+ ```tsx
1038
+ { type: RuleType.htmlComment, text: "<!-- comment -->" }
1039
+ ```
1040
+ - `RuleType.htmlSelfClosing` - Self-closing HTML tags
1041
+ ```tsx
1042
+ { type: RuleType.htmlSelfClosing, tag: "img", attrs: { src: "image.png" } }
1043
+ ```
1036
1044
 
1037
- ### Example AST Structure
1045
+ #### Example AST Structure
1038
1046
 
1039
1047
  ````tsx
1040
1048
  import { parser, RuleType } from 'markdown-to-jsx'
@@ -1093,9 +1101,9 @@ console.log('code')
1093
1101
 
1094
1102
  ````
1095
1103
 
1096
- ### Type Checking
1104
+ #### Type Checking
1097
1105
 
1098
- Use `RuleType` constants to check node types:
1106
+ Use the `RuleType` enum to identify AST nodes:
1099
1107
 
1100
1108
  ```tsx
1101
1109
  import { RuleType } from 'markdown-to-jsx'
@@ -1112,6 +1120,94 @@ if (node.type === RuleType.heading) {
1112
1120
  - Use `compiler` when you need React JSX output from markdown (the component uses this internally).
1113
1121
  - Use `parser` + `astToJSX` when you need the AST for custom processing before rendering to JSX, or just the AST itself.
1114
1122
 
1123
+ ### Gotchas
1124
+
1125
+ #### Passing props to stringified React components
1126
+
1127
+ Using the [`options.overrides`](#optionsoverrides---rendering-arbitrary-react-components) functionality to render React components, props are passed into the component in stringifed form. It is up to you to parse the string to make use of the data.
1128
+
1129
+ ```tsx
1130
+ const Table: React.FC<
1131
+ JSX.IntrinsicElements['table'] & {
1132
+ columns: string
1133
+ dataSource: string
1134
+ }
1135
+ > = ({ columns, dataSource, ...props }) => {
1136
+ const parsedColumns = JSON.parse(columns)
1137
+ const parsedData = JSON.parse(dataSource)
1138
+
1139
+ return (
1140
+ <div {...props}>
1141
+ <h1>Columns</h1>
1142
+ {parsedColumns.map(column => (
1143
+ <span key={column.key}>{column.title}</span>
1144
+ ))}
1145
+
1146
+ <h2>Data</h2>
1147
+ {parsedData.map(datum => (
1148
+ <span key={datum.key}>{datum.Month}</span>
1149
+ ))}
1150
+ </div>
1151
+ )
1152
+ }
1153
+
1154
+ /**
1155
+ * Example HTML in markdown:
1156
+ *
1157
+ * <Table
1158
+ * columns={[{ title: 'Month', dataIndex: 'Month', key: 'Month' }]}
1159
+ * dataSource={[
1160
+ * {
1161
+ * Month: '2024-09-01',
1162
+ * 'Forecasted Revenue': '$3,137,678.85',
1163
+ * 'Forecasted Expenses': '$2,036,660.28',
1164
+ * key: 0,
1165
+ * },
1166
+ * ]}
1167
+ * />
1168
+ */
1169
+ ```
1170
+
1171
+ #### Significant indentation inside arbitrary HTML
1172
+
1173
+ People usually write HTML like this:
1174
+
1175
+ ```html
1176
+ <div>Hey, how are you?</div>
1177
+ ```
1178
+
1179
+ Note the leading spaces before the inner content. This sort of thing unfortunately clashes with existing markdown syntaxes since 4 spaces === a code block and other similar collisions.
1180
+
1181
+ To get around this, `markdown-to-jsx` left-trims approximately as much whitespace as the first line inside the HTML block. So for example:
1182
+
1183
+ ```html
1184
+ <div># Hello How are you?</div>
1185
+ ```
1186
+
1187
+ The two leading spaces in front of "# Hello" would be left-trimmed from all lines inside the HTML block. In the event that there are varying amounts of indentation, only the amount of the first line is trimmed.
1188
+
1189
+ > NOTE! These syntaxes work just fine when you aren't writing arbitrary HTML wrappers inside your markdown. This is very much an edge case of an edge case. 🙃
1190
+
1191
+ #### Code blocks
1192
+
1193
+ ⛔️
1194
+
1195
+ ```md
1196
+ <div>
1197
+ var some = code();
1198
+ </div>
1199
+ ```
1200
+
1201
+
1202
+
1203
+ ````md
1204
+ <div>
1205
+ ```js
1206
+ var some = code();
1207
+ ```
1208
+ </div>
1209
+ ````
1210
+
1115
1211
  ## Changelog
1116
1212
 
1117
1213
  See [Github Releases](https://github.com/quantizor/markdown-to-jsx/releases).