UNPKG

17.5 kBMarkdownView Raw
1# html-react-parser
2
3[![NPM](https://nodei.co/npm/html-react-parser.png)](https://nodei.co/npm/html-react-parser/)
4
5[![NPM version](https://img.shields.io/npm/v/html-react-parser.svg)](https://www.npmjs.com/package/html-react-parser)
6[![Build Status](https://github.com/remarkablemark/html-react-parser/workflows/build/badge.svg?branch=master)](https://github.com/remarkablemark/html-react-parser/actions?query=workflow%3Abuild)
7[![codecov](https://codecov.io/gh/remarkablemark/html-react-parser/branch/master/graph/badge.svg?token=wosFd1DBIR)](https://codecov.io/gh/remarkablemark/html-react-parser)
8[![Dependency status](https://david-dm.org/remarkablemark/html-react-parser.svg)](https://david-dm.org/remarkablemark/html-react-parser)
9[![NPM downloads](https://img.shields.io/npm/dm/html-react-parser.svg?style=flat-square)](https://www.npmjs.com/package/html-react-parser)
10[![Discord](https://img.shields.io/discord/422421589582282752.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/njExwXdrRJ)
11
12HTML to React parser that works on both the server (Node.js) and the client (browser):
13
14```
15HTMLReactParser(string[, options])
16```
17
18The parser converts an HTML string to one or more [React elements](https://reactjs.org/docs/react-api.html#creating-react-elements).
19
20To replace an element with another element, check out the [`replace`](#replace) option.
21
22#### Example
23
24```js
25const parse = require('html-react-parser');
26parse('<p>Hello, World!</p>'); // React.createElement('p', {}, 'Hello, World!')
27```
28
29[Repl.it](https://repl.it/@remarkablemark/html-react-parser) | [JSFiddle](https://jsfiddle.net/remarkablemark/7v86d800/) | [CodeSandbox](https://codesandbox.io/s/940pov1l4w) | [TypeScript](https://codesandbox.io/s/html-react-parser-z0kp6) | [Examples](https://github.com/remarkablemark/html-react-parser/tree/master/examples)
30
31<details>
32<summary>Table of Contents</summary>
33
34- [Install](#install)
35- [Usage](#usage)
36 - [replace](#replace)
37 - [replace with TypeScript](#replace-with-typescript)
38 - [replace element and children](#replace-element-and-children)
39 - [replace element attributes](#replace-element-attributes)
40 - [replace and remove element](#replace-and-remove-element)
41 - [library](#library)
42 - [htmlparser2](#htmlparser2)
43 - [trim](#trim)
44- [Migration](#migration)
45 - [v1.0.0](#v100)
46- [FAQ](#faq)
47 - [Is this XSS safe?](#is-this-xss-safe)
48 - [Does invalid HTML get sanitized?](#does-invalid-html-get-sanitized)
49 - [Are `<script>` tags parsed?](#are-script-tags-parsed)
50 - [Attributes aren't getting called](#attributes-arent-getting-called)
51 - [Parser throws an error](#parser-throws-an-error)
52 - [Is SSR supported?](#is-ssr-supported)
53 - [Elements aren't nested correctly](#elements-arent-nested-correctly)
54 - [Warning: validateDOMNesting(...): Whitespace text nodes cannot appear as a child of table](#warning-validatedomnesting-whitespace-text-nodes-cannot-appear-as-a-child-of-table)
55 - [Don't change case of tags](#dont-change-case-of-tags)
56 - [TS Error: Property 'attribs' does not exist on type 'DOMNode'](#ts-error-property-attribs-does-not-exist-on-type-domnode)
57 - [Can I enable `trim` for certain elements?](#can-i-enable-trim-for-certain-elements)
58 - [Webpack build warnings](#webpack-build-warnings)
59- [Performance](#performance)
60- [Contributors](#contributors)
61 - [Code Contributors](#code-contributors)
62 - [Financial Contributors](#financial-contributors)
63 - [Individuals](#individuals)
64 - [Organizations](#organizations)
65- [Support](#support)
66- [License](#license)
67
68</details>
69
70## Install
71
72[NPM](https://www.npmjs.com/package/html-react-parser):
73
74```sh
75npm install html-react-parser --save
76```
77
78[Yarn](https://yarnpkg.com/package/html-react-parser):
79
80```sh
81yarn add html-react-parser
82```
83
84[CDN](https://unpkg.com/html-react-parser/):
85
86```html
87<!-- HTMLReactParser depends on React -->
88<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
89<script src="https://unpkg.com/html-react-parser@latest/dist/html-react-parser.min.js"></script>
90<script>
91 window.HTMLReactParser(/* string */);
92</script>
93```
94
95## Usage
96
97Import or require the module:
98
99```js
100// ES Modules
101import parse from 'html-react-parser';
102
103// CommonJS
104const parse = require('html-react-parser');
105```
106
107Parse single element:
108
109```js
110parse('<h1>single</h1>');
111```
112
113Parse multiple elements:
114
115```js
116parse('<li>Item 1</li><li>Item 2</li>');
117```
118
119Make sure to render parsed adjacent elements under a parent element:
120
121```jsx
122<ul>
123 {parse(`
124 <li>Item 1</li>
125 <li>Item 2</li>
126 `)}
127</ul>
128```
129
130Parse nested elements:
131
132```js
133parse('<body><p>Lorem ipsum</p></body>');
134```
135
136Parse element with attributes:
137
138```js
139parse(
140 '<hr id="foo" class="bar" data-attr="baz" custom="qux" style="top:42px;">'
141);
142```
143
144### replace
145
146The `replace` option allows you to replace an element with another element.
147
148The `replace` callback's first argument is [domhandler](https://github.com/fb55/domhandler#example)'s node:
149
150```js
151parse('<br>', {
152 replace: domNode => {
153 console.dir(domNode, { depth: null });
154 }
155});
156```
157
158Console output:
159
160```js
161Element {
162 type: 'tag',
163 parent: null,
164 prev: null,
165 next: null,
166 startIndex: null,
167 endIndex: null,
168 children: [],
169 name: 'br',
170 attribs: {}
171}
172```
173
174The element is replaced if a **valid** React element is returned:
175
176```jsx
177parse('<p id="replace">text</p>', {
178 replace: domNode => {
179 if (domNode.attribs && domNode.attribs.id === 'replace') {
180 return <span>replaced</span>;
181 }
182 }
183});
184```
185
186#### replace with TypeScript
187
188For TypeScript projects, you may need to check that `domNode` is an instance of domhandler's `Element`:
189
190```tsx
191import { HTMLReactParserOptions } from 'html-react-parser';
192import { Element } from 'domhandler/lib/node';
193
194const options: HTMLReactParserOptions = {
195 replace: domNode => {
196 if (domNode instanceof Element && domNode.attribs) {
197 // ...
198 }
199 }
200};
201```
202
203If you're having issues with `domNode instanceof Element`, try this [alternative solution](https://github.com/remarkablemark/html-react-parser/issues/221#issuecomment-771600574).
204
205#### replace element and children
206
207Replace the element and its children (see [demo](https://repl.it/@remarkablemark/html-react-parser-replace-example)):
208
209```jsx
210import parse, { domToReact } from 'html-react-parser';
211
212const html = `
213 <p id="main">
214 <span class="prettify">
215 keep me and make me pretty!
216 </span>
217 </p>
218`;
219
220const options = {
221 replace: ({ attribs, children }) => {
222 if (!attribs) {
223 return;
224 }
225
226 if (attribs.id === 'main') {
227 return <h1 style={{ fontSize: 42 }}>{domToReact(children, options)}</h1>;
228 }
229
230 if (attribs.class === 'prettify') {
231 return (
232 <span style={{ color: 'hotpink' }}>
233 {domToReact(children, options)}
234 </span>
235 );
236 }
237 }
238};
239
240parse(html, options);
241```
242
243HTML output:
244
245<!-- prettier-ignore-start -->
246
247```html
248<h1 style="font-size:42px">
249 <span style="color:hotpink">
250 keep me and make me pretty!
251 </span>
252</h1>
253```
254
255<!-- prettier-ignore-end -->
256
257#### replace element attributes
258
259Convert DOM attributes to React props with `attributesToProps`:
260
261```jsx
262import parse, { attributesToProps } from 'html-react-parser';
263
264const html = `
265 <main class="prettify" style="background: #fff; text-align: center;" />
266`;
267
268const options = {
269 replace: domNode => {
270 if (domNode.attribs && domNode.name === 'main') {
271 const props = attributesToProps(domNode.attribs);
272 return <div {...props} />;
273 }
274 }
275};
276
277parse(html, options);
278```
279
280HTML output:
281
282```html
283<div class="prettify" style="background:#fff;text-align:center"></div>
284```
285
286#### replace and remove element
287
288[Exclude](https://repl.it/@remarkablemark/html-react-parser-56) an element from rendering by replacing it with `<React.Fragment>`:
289
290```jsx
291parse('<p><br id="remove"></p>', {
292 replace: ({ attribs }) => attribs && attribs.id === 'remove' && <></>
293});
294```
295
296HTML output:
297
298```html
299<p></p>
300```
301
302### library
303
304The `library` option specifies the UI library. The default library is **React**.
305
306To use Preact:
307
308```js
309parse('<br>', {
310 library: require('preact')
311});
312```
313
314Or a custom library:
315
316```js
317parse('<br>', {
318 library: {
319 cloneElement: () => {
320 /* ... */
321 },
322 createElement: () => {
323 /* ... */
324 },
325 isValidElement: () => {
326 /* ... */
327 }
328 }
329});
330```
331
332### htmlparser2
333
334> `htmlparser2` options **do not work on the client-side** (browser) and **only works on the server-side** (Node.js). By overriding `htmlparser2` options, universal rendering can break.
335
336Default [htmlparser2 options](https://github.com/fb55/htmlparser2/wiki/Parser-options#option-xmlmode) can be overridden in >=[0.12.0](https://github.com/remarkablemark/html-react-parser/tree/v0.12.0).
337
338To enable [`xmlMode`](https://github.com/fb55/htmlparser2/wiki/Parser-options#option-xmlmode):
339
340```js
341parse('<p /><p />', {
342 htmlparser2: {
343 xmlMode: true
344 }
345});
346```
347
348### trim
349
350By default, whitespace is preserved:
351
352```js
353parse('<br>\n'); // [React.createElement('br'), '\n']
354```
355
356To remove whitespace, enable the `trim` option:
357
358```js
359parse('<br>\n', { trim: true }); // React.createElement('br')
360```
361
362This fixes the warning:
363
364```
365Warning: validateDOMNesting(...): Whitespace text nodes cannot appear as a child of <table>. Make sure you don't have any extra whitespace between tags on each line of your source code.
366```
367
368However, intentional whitespace may be stripped out:
369
370```js
371parse('<p> </p>', { trim: true }); // React.createElement('p')
372```
373
374## Migration
375
376### v1.0.0
377
378TypeScript projects will need to update the types in [v1.0.0](https://github.com/remarkablemark/html-react-parser/releases/tag/v1.0.0).
379
380For the `replace` option, you may need to do the following:
381
382```tsx
383import { Element } from 'domhandler/lib/node';
384
385parse('<br class="remove">', {
386 replace: domNode => {
387 if (domNode instanceof Element && domNode.attribs.class === 'remove') {
388 return <></>;
389 }
390 }
391});
392```
393
394Since [v1.1.1](https://github.com/remarkablemark/html-react-parser/releases/tag/v1.1.1), Internet Explorer 9 (IE9) is no longer supported.
395
396## FAQ
397
398### Is this XSS safe?
399
400No, this library is _**not**_ [XSS (cross-site scripting)](https://wikipedia.org/wiki/Cross-site_scripting) safe. See [#94](https://github.com/remarkablemark/html-react-parser/issues/94).
401
402### Does invalid HTML get sanitized?
403
404No, this library does _**not**_ sanitize HTML. See [#124](https://github.com/remarkablemark/html-react-parser/issues/124), [#125](https://github.com/remarkablemark/html-react-parser/issues/125), and [#141](https://github.com/remarkablemark/html-react-parser/issues/141).
405
406### Are `<script>` tags parsed?
407
408Although `<script>` tags and their contents are rendered on the server-side, they're not evaluated on the client-side. See [#98](https://github.com/remarkablemark/html-react-parser/issues/98).
409
410### Attributes aren't getting called
411
412The reason why your HTML attributes aren't getting called is because [inline event handlers](https://developer.mozilla.org/docs/Web/Guide/Events/Event_handlers) (e.g., `onclick`) are parsed as a _string_ rather than a _function_. See [#73](https://github.com/remarkablemark/html-react-parser/issues/73).
413
414### Parser throws an error
415
416If the parser throws an erorr, check if your arguments are valid. See ["Does invalid HTML get sanitized?"](#does-invalid-html-get-sanitized).
417
418### Is SSR supported?
419
420Yes, server-side rendering on Node.js is supported by this library. See [demo](https://repl.it/@remarkablemark/html-react-parser-SSR).
421
422### Elements aren't nested correctly
423
424If your elements are nested incorrectly, check to make sure your [HTML markup is valid](https://validator.w3.org/). The HTML to DOM parsing will be affected if you're using self-closing syntax (`/>`) on non-void elements:
425
426```js
427parse('<div /><div />'); // returns single element instead of array of elements
428```
429
430See [#158](https://github.com/remarkablemark/html-react-parser/issues/158).
431
432### Warning: validateDOMNesting(...): Whitespace text nodes cannot appear as a child of table
433
434Enable the [trim](#trim) option. See [#155](https://github.com/remarkablemark/html-react-parser/issues/155).
435
436### Don't change case of tags
437
438Tags are lowercased by default. To prevent that from happening, pass the [htmlparser2 option](#htmlparser2):
439
440```js
441const options = {
442 htmlparser2: {
443 lowerCaseTags: false
444 }
445};
446parse('<CustomElement>', options); // React.createElement('CustomElement')
447```
448
449> **Warning**: By preserving case-sensitivity of the tags, you may get rendering warnings like:
450>
451> ```
452> Warning: <CustomElement> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.
453> ```
454
455See [#62](https://github.com/remarkablemark/html-react-parser/issues/62) and [example](https://repl.it/@remarkablemark/html-react-parser-62).
456
457### TS Error: Property 'attribs' does not exist on type 'DOMNode'
458
459The TypeScript error occurs because `DOMNode` needs be an instance of domhandler's `Element`. See [migration](#migration) or [#199](https://github.com/remarkablemark/html-react-parser/issues/199).
460
461### Can I enable `trim` for certain elements?
462
463Yes, you can enable or disable [`trim`](#trim) for certain elements using the [`replace`](#replace) option. See [#205](https://github.com/remarkablemark/html-react-parser/issues/205).
464
465### Webpack build warnings
466
467If you see the Webpack build warning:
468
469```
470export 'default' (imported as 'parse') was not found in 'html-react-parser'
471```
472
473Then update your Webpack config to:
474
475```js
476// webpack.config.js
477module.exports = {
478 // ...
479 resolve: {
480 mainFields: ['browser', 'main', 'module']
481 }
482};
483```
484
485See [#238](https://github.com/remarkablemark/html-react-parser/issues/238) and [#213](https://github.com/remarkablemark/html-react-parser/issues/213).
486
487## Performance
488
489Run benchmark:
490
491```sh
492npm run test:benchmark
493```
494
495Output of benchmark run on MacBook Pro 2017:
496
497```
498html-to-react - Single x 415,186 ops/sec ±0.92% (85 runs sampled)
499html-to-react - Multiple x 139,780 ops/sec ±2.32% (87 runs sampled)
500html-to-react - Complex x 8,118 ops/sec ±2.99% (82 runs sampled)
501```
502
503Run [Size Limit](https://github.com/ai/size-limit):
504
505```sh
506npx size-limit
507```
508
509## Contributors
510
511### Code Contributors
512
513This project exists thanks to all the people who contribute. [[Contribute](https://github.com/remarkablemark/html-react-parser/blob/master/CONTRIBUTING.md)].
514
515[![Code Contributors](https://opencollective.com/html-react-parser/contributors.svg?width=890&button=false)](https://github.com/remarkablemark/html-react-parser/graphs/contributors)
516
517### Financial Contributors
518
519Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/html-react-parser/contribute)]
520
521#### Individuals
522
523[![Financial Contributors - Individuals](https://opencollective.com/html-react-parser/individuals.svg?width=890)](https://opencollective.com/html-react-parser)
524
525#### Organizations
526
527Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/html-react-parser/contribute)]
528
529[![Financial Contributors - Organization 0](https://opencollective.com/html-react-parser/organization/0/avatar.svg)](https://opencollective.com/html-react-parser/organization/0/website)
530[![Financial Contributors - Organization 1](https://opencollective.com/html-react-parser/organization/1/avatar.svg)](https://opencollective.com/html-react-parser/organization/1/website)
531[![Financial Contributors - Organization 2](https://opencollective.com/html-react-parser/organization/2/avatar.svg)](https://opencollective.com/html-react-parser/organization/2/website)
532[![Financial Contributors - Organization 3](https://opencollective.com/html-react-parser/organization/3/avatar.svg)](https://opencollective.com/html-react-parser/organization/3/website)
533[![Financial Contributors - Organization 4](https://opencollective.com/html-react-parser/organization/4/avatar.svg)](https://opencollective.com/html-react-parser/organization/4/website)
534[![Financial Contributors - Organization 5](https://opencollective.com/html-react-parser/organization/5/avatar.svg)](https://opencollective.com/html-react-parser/organization/5/website)
535[![Financial Contributors - Organization 6](https://opencollective.com/html-react-parser/organization/6/avatar.svg)](https://opencollective.com/html-react-parser/organization/6/website)
536[![Financial Contributors - Organization 7](https://opencollective.com/html-react-parser/organization/7/avatar.svg)](https://opencollective.com/html-react-parser/organization/7/website)
537[![Financial Contributors - Organization 8](https://opencollective.com/html-react-parser/organization/8/avatar.svg)](https://opencollective.com/html-react-parser/organization/8/website)
538[![Financial Contributors - Organization 9](https://opencollective.com/html-react-parser/organization/9/avatar.svg)](https://opencollective.com/html-react-parser/organization/9/website)
539
540## Support
541
542- [GitHub Sponsors](https://b.remarkabl.org/github-sponsors)
543- [Open Collective](https://b.remarkabl.org/open-collective-html-react-parser)
544- [Tidelift](https://b.remarkabl.org/tidelift-html-react-parser)
545- [Patreon](https://b.remarkabl.org/patreon)
546- [Ko-fi](https://b.remarkabl.org/ko-fi)
547- [Liberapay](https://b.remarkabl.org/liberapay)
548- [Teepsring](https://b.remarkabl.org/teespring)
549
550## License
551
552[MIT](https://github.com/remarkablemark/html-react-parser/blob/master/LICENSE)