markdown-to-jsx 9.0.0-rc.1 → 9.0.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)
@@ -39,24 +44,19 @@ Some special features of the library:
39
44
  - [options.slugify](#optionsslugify)
40
45
  - [options.disableAutoLink](#optionsdisableautolink)
41
46
  - [options.disableParsingRawHTML](#optionsdisableparsingrawhtml)
47
+ - [options.tagfilter](#optionstagfilter)
42
48
  - [Syntax highlighting](#syntax-highlighting)
43
49
  - [Handling shortcodes](#handling-shortcodes)
44
50
  - [Getting the smallest possible bundle size](#getting-the-smallest-possible-bundle-size)
45
51
  - [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)
52
+ - [AST Anatomy](#ast-anatomy)
53
+ - [Node Types](#node-types)
54
+ - [Example AST Structure](#example-ast-structure)
55
+ - [Type Checking](#type-checking)
56
+ - [Gotchas](#gotchas)
57
+ - [Passing props to stringified React components](#passing-props-to-stringified-react-components)
58
+ - [Significant indentation inside arbitrary HTML](#significant-indentation-inside-arbitrary-html)
49
59
  - [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
60
  - [Changelog](#changelog)
61
61
  - [Donate](#donate)
62
62
 
@@ -92,6 +92,19 @@ import { compiler } from 'markdown-to-jsx'
92
92
  compiler('&le; symbol') // All entities supported automatically
93
93
  ```
94
94
 
95
+ - **`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.
96
+
97
+ ```typescript
98
+ // Before (v8) - tags rendered as JSX elements
99
+ compiler('<script>alert("xss")</script>') // Rendered as <script> element
100
+
101
+ // After (v9) - tags escaped by default
102
+ compiler('<script>alert("xss")</script>') // Renders as <span>&lt;script&gt;</span>
103
+
104
+ // To restore old behavior:
105
+ compiler('<script>alert("xss")</script>', { tagfilter: false })
106
+ ```
107
+
95
108
  **New Features:**
96
109
 
97
110
  - **New `parser` function**: Provides direct access to the parsed AST without rendering. This is the recommended way to get AST nodes.
@@ -204,7 +217,75 @@ render(<Markdown># Hello world!</Markdown>, document.body)
204
217
 
205
218
  \* **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
219
 
207
- ### Parsing Options
220
+ ### Entry Points
221
+
222
+ `markdown-to-jsx` provides multiple entry points for different use cases:
223
+
224
+ #### Main
225
+
226
+ The legacy\*default entry point exports everything, including the React compiler and component:
227
+
228
+ ```tsx
229
+ import Markdown, { compiler, parser } from 'markdown-to-jsx'
230
+ ```
231
+
232
+ _The React code in this entry point is deprecated and will be removed in a future major release, migrate to `markdown-to-jsx/react`._
233
+
234
+ #### React
235
+
236
+ For React-specific usage, import from the `/react` entry point:
237
+
238
+ ```tsx
239
+ import Markdown, { compiler, parser, astToJSX } from 'markdown-to-jsx/react'
240
+
241
+ // Use compiler for markdown → JSX
242
+ const jsxElement = compiler('# Hello world')
243
+
244
+ const markdown = `# Hello world`
245
+
246
+ function App() {
247
+ return <Markdown children={markdown} />
248
+ }
249
+
250
+ // Or use parser + astToJSX for total control
251
+ const ast = parser('# Hello world')
252
+ const jsxElement2 = astToJSX(ast)
253
+ ```
254
+
255
+ #### HTML
256
+
257
+ For HTML string output (server-side rendering), import from the `/html` entry point:
258
+
259
+ ```tsx
260
+ import { compiler, html, parser } from 'markdown-to-jsx/html'
261
+
262
+ // Convenience function that combines parsing and HTML rendering
263
+ const htmlString = compiler('# Hello world')
264
+ // Returns: '<h1>Hello world</h1>'
265
+
266
+ // Or use parser + html separately for more control
267
+ const ast = parser('# Hello world')
268
+ const htmlString2 = html(ast)
269
+ ```
270
+
271
+ #### Markdown
272
+
273
+ For markdown-to-markdown compilation (normalization and formatting), import from the `/markdown` entry point:
274
+
275
+ ```typescript
276
+ import { compiler, astToMarkdown, parser } from 'markdown-to-jsx/markdown'
277
+
278
+ // Convenience function that parses and recompiles markdown
279
+ const normalizedMarkdown = compiler('# Hello world\n\nExtra spaces!')
280
+ // Returns: '# Hello world\n\nExtra spaces!\n'
281
+
282
+ // Or work with AST directly
283
+ const ast = parser('# Hello world')
284
+ const normalizedMarkdown2 = astToMarkdown(ast)
285
+ // Returns: '# Hello world\n'
286
+ ```
287
+
288
+ ### Library Options
208
289
 
209
290
  #### options.forceBlock
210
291
 
@@ -283,6 +364,24 @@ compiler('One\n\nTwo\n\nThree', { wrapper: null })
283
364
 
284
365
  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
366
 
367
+ #### options.wrapperProps
368
+
369
+ Props to apply to the wrapper element when `wrapper` is used.
370
+
371
+ ```tsx
372
+ <Markdown options={{
373
+ wrapper: 'article',
374
+ wrapperProps: { className: 'post', 'data-testid': 'markdown-content' }
375
+ }}>
376
+ # Hello World
377
+ </Markdown>
378
+
379
+ // renders
380
+ <article class="post" data-testid="markdown-content">
381
+ <h1>Hello World</h1>
382
+ </article>
383
+ ```
384
+
286
385
  #### options.forceWrapper
287
386
 
288
387
  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 +399,15 @@ By default, the compiler does not wrap the rendered contents if there is only a
300
399
 
301
400
  #### options.overrides - Void particular banned tags
302
401
 
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:
402
+ 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.
403
+
404
+ **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:
405
+
406
+ - Remove additional tags not covered by `tagfilter` (like `object`)
407
+ - Have more control over tag removal vs. escaping
408
+ - Disable `tagfilter` but still want to remove specific tags
409
+
410
+ For example, to void the `iframe` tag:
304
411
 
305
412
  ```tsx
306
413
  import Markdown from 'markdown-to-jsx'
@@ -317,7 +424,7 @@ render(
317
424
  // renders: ""
318
425
  ```
319
426
 
320
- The library does not void any tags by default to avoid surprising behavior for personal use cases.
427
+ 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
428
 
322
429
  #### options.overrides - Override Any HTML Tag's Representation
323
430
 
@@ -656,6 +763,27 @@ compiler('This text has <span>html</span> in it but it won't be rendered', { dis
656
763
  <span>This text has &lt;span&gt;html&lt;/span&gt; in it but it won't be rendered</span>
657
764
  ```
658
765
 
766
+ #### options.tagfilter
767
+
768
+ 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`.
769
+
770
+ ```tsx
771
+ // Tags are escaped by default (GFM-compliant)
772
+ compiler('<script>alert("xss")</script>')
773
+ // HTML output: '<span>&lt;script&gt;</span>'
774
+ // React output: <span>&lt;script&gt;</span>
775
+
776
+ // Disable tag filtering:
777
+ compiler('<script>alert("xss")</script>', { tagfilter: false })
778
+ // HTML output: '<script></script>'
779
+ // React output: <script></script>
780
+ ```
781
+
782
+ **Note**: Even when `tagfilter` is disabled, other security measures remain active:
783
+
784
+ - URL sanitization preventing `javascript:` and `vbscript:` schemes in `href` and `src` attributes
785
+ - Protection against `data:` URLs (except safe `data:image/*` MIME types)
786
+
659
787
  ### Syntax highlighting
660
788
 
661
789
  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 +899,13 @@ Here are instructions for some of the popular bundlers:
771
899
 
772
900
  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
901
 
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
902
+ ### AST Anatomy
960
903
 
961
904
  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
905
 
963
906
  **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
907
 
965
- ### Node Types
908
+ #### Node Types
966
909
 
967
910
  The AST consists of the following node types (use `RuleType` to check node types):
968
911
 
@@ -987,7 +930,7 @@ The AST consists of the following node types (use `RuleType` to check node types
987
930
  - `RuleType.orderedList` / `RuleType.unorderedList` - Lists
988
931
  ```tsx
989
932
  { type: RuleType.orderedList, items: [[...]], start?: 1 }
990
- { type: RuleType.unorderedList, items: [[...]], ordered: false }
933
+ { type: RuleType.unorderedList, items: [[...]] }
991
934
  ```
992
935
  - `RuleType.table` - Tables
993
936
  ```tsx
@@ -1020,21 +963,30 @@ The AST consists of the following node types (use `RuleType` to check node types
1020
963
  ```tsx
1021
964
  { type: RuleType.image, target: "image.png", alt: "description" }
1022
965
  ```
1023
- - `RuleType.refLink` / `RuleType.refImage` - Reference-style links/images
1024
- ```tsx
1025
- { type: RuleType.refLink, ref: "linkref", children: [...] }
1026
- ```
1027
966
 
1028
967
  **Other nodes:**
1029
968
 
1030
969
  - `RuleType.breakLine` - Hard line breaks (` `)
1031
970
  - `RuleType.breakThematic` - Horizontal rules (`---`)
1032
971
  - `RuleType.gfmTask` - GFM task list items (`- [ ]`)
972
+ - `RuleType.ref` - Reference definition node (not rendered, stored in refCollection)
1033
973
  - `RuleType.refCollection` - Reference definitions collection (appears at AST root, includes footnotes with `^` prefix)
1034
974
  - `RuleType.footnote` - Footnote definition node (not rendered, stored in refCollection)
1035
975
  - `RuleType.footnoteReference` - Footnote reference (`[^identifier]`)
976
+ - `RuleType.frontmatter` - YAML frontmatter blocks
977
+ ```tsx
978
+ { type: RuleType.frontmatter, text: "---\ntitle: My Title\n---" }
979
+ ```
980
+ - `RuleType.htmlComment` - HTML comment nodes
981
+ ```tsx
982
+ { type: RuleType.htmlComment, text: "<!-- comment -->" }
983
+ ```
984
+ - `RuleType.htmlSelfClosing` - Self-closing HTML tags
985
+ ```tsx
986
+ { type: RuleType.htmlSelfClosing, tag: "img", attrs: { src: "image.png" } }
987
+ ```
1036
988
 
1037
- ### Example AST Structure
989
+ #### Example AST Structure
1038
990
 
1039
991
  ````tsx
1040
992
  import { parser, RuleType } from 'markdown-to-jsx'
@@ -1093,9 +1045,9 @@ console.log('code')
1093
1045
 
1094
1046
  ````
1095
1047
 
1096
- ### Type Checking
1048
+ #### Type Checking
1097
1049
 
1098
- Use `RuleType` constants to check node types:
1050
+ Use the `RuleType` enum to identify AST nodes:
1099
1051
 
1100
1052
  ```tsx
1101
1053
  import { RuleType } from 'markdown-to-jsx'
@@ -1112,6 +1064,94 @@ if (node.type === RuleType.heading) {
1112
1064
  - Use `compiler` when you need React JSX output from markdown (the component uses this internally).
1113
1065
  - Use `parser` + `astToJSX` when you need the AST for custom processing before rendering to JSX, or just the AST itself.
1114
1066
 
1067
+ ### Gotchas
1068
+
1069
+ #### Passing props to stringified React components
1070
+
1071
+ 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.
1072
+
1073
+ ```tsx
1074
+ const Table: React.FC<
1075
+ JSX.IntrinsicElements['table'] & {
1076
+ columns: string
1077
+ dataSource: string
1078
+ }
1079
+ > = ({ columns, dataSource, ...props }) => {
1080
+ const parsedColumns = JSON.parse(columns)
1081
+ const parsedData = JSON.parse(dataSource)
1082
+
1083
+ return (
1084
+ <div {...props}>
1085
+ <h1>Columns</h1>
1086
+ {parsedColumns.map(column => (
1087
+ <span key={column.key}>{column.title}</span>
1088
+ ))}
1089
+
1090
+ <h2>Data</h2>
1091
+ {parsedData.map(datum => (
1092
+ <span key={datum.key}>{datum.Month}</span>
1093
+ ))}
1094
+ </div>
1095
+ )
1096
+ }
1097
+
1098
+ /**
1099
+ * Example HTML in markdown:
1100
+ *
1101
+ * <Table
1102
+ * columns={[{ title: 'Month', dataIndex: 'Month', key: 'Month' }]}
1103
+ * dataSource={[
1104
+ * {
1105
+ * Month: '2024-09-01',
1106
+ * 'Forecasted Revenue': '$3,137,678.85',
1107
+ * 'Forecasted Expenses': '$2,036,660.28',
1108
+ * key: 0,
1109
+ * },
1110
+ * ]}
1111
+ * />
1112
+ */
1113
+ ```
1114
+
1115
+ #### Significant indentation inside arbitrary HTML
1116
+
1117
+ People usually write HTML like this:
1118
+
1119
+ ```html
1120
+ <div>Hey, how are you?</div>
1121
+ ```
1122
+
1123
+ 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.
1124
+
1125
+ To get around this, `markdown-to-jsx` left-trims approximately as much whitespace as the first line inside the HTML block. So for example:
1126
+
1127
+ ```html
1128
+ <div># Hello How are you?</div>
1129
+ ```
1130
+
1131
+ 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.
1132
+
1133
+ > 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. 🙃
1134
+
1135
+ #### Code blocks
1136
+
1137
+ ⛔️
1138
+
1139
+ ```md
1140
+ <div>
1141
+ var some = code();
1142
+ </div>
1143
+ ```
1144
+
1145
+
1146
+
1147
+ ````md
1148
+ <div>
1149
+ ```js
1150
+ var some = code();
1151
+ ```
1152
+ </div>
1153
+ ````
1154
+
1115
1155
  ## Changelog
1116
1156
 
1117
1157
  See [Github Releases](https://github.com/quantizor/markdown-to-jsx/releases).