HTML to React parser that works on both the server (Node.js) and the client (browser):
HTMLReactParser(string[, options])
The parser converts an HTML string to one or more React elements.
To replace an element with another element, check out the replace option.
Example
import parse from 'html-react-parser'; parse('<p>Hello, World!</p>'); // React.createElement('p', {}, 'Hello, World!')
StackBlitz | TypeScript | JSFiddle | Examples
Table of Contents- Install
- Usage
- Migration
- FAQ
- Is this XSS safe?
- Does invalid HTML get sanitized?
- Are
<script>tags parsed? - Attributes aren't getting called
- Parser throws an error
- Is SSR supported?
- Elements aren't nested correctly
- Don't change case of tags
- TS Error: Property 'attribs' does not exist on type 'DOMNode'
- Can I enable
trimfor certain elements? - Webpack build warnings
- TypeScript error
- Performance
- Contributors
- Support
- License
Install
NPM:
npm install html-react-parser --save
Yarn:
yarn add html-react-parser
CDN:
<!-- HTMLReactParser depends on React --> <script src="https://unpkg.com/react@18/umd/react.production.min.js"></script> <script src="https://unpkg.com/html-react-parser@latest/dist/html-react-parser.min.js"></script> <script> window.HTMLReactParser(/* string */); </script>
Usage
Import ES module:
import parse from 'html-react-parser';
Or require CommonJS module:
const parse = require('html-react-parser').default;
Parse single element:
parse('<h1>single</h1>');
Parse multiple elements:
parse('<li>Item 1</li><li>Item 2</li>');
Make sure to render parsed adjacent elements under a parent element:
<ul> {parse(` <li>Item 1</li> <li>Item 2</li> `)} </ul>
Parse nested elements:
parse('<body><p>Lorem ipsum</p></body>');
Parse element with attributes:
parse( '<hr id="foo" class="bar" data-attr="baz" custom="qux" style="top:42px;">', );
replace
The replace option allows you to replace an element with another element.
The replace callback's first argument is domhandler's node:
parse('<br>', { replace(domNode) { console.dir(domNode, { depth: null }); }, });
Element { type: 'tag', parent: null, prev: null, next: null, startIndex: null, endIndex: null, children: [], name: 'br', attribs: {} }
The element is replaced if a valid React element is returned:
parse('<p id="replace">text</p>', { replace(domNode) { if (domNode.attribs && domNode.attribs.id === 'replace') { return <span>replaced</span>; } }, });
The second argument is the index:
parse('<br>', { replace(domNode, index) { console.assert(typeof index === 'number'); }, });
Note
The index will restart at 0 when traversing the node's children so don't rely on index being a unique key (see #1259).
replace with TypeScript
You need to check that domNode is an instance of domhandler's Element:
import { HTMLReactParserOptions, Element } from 'html-react-parser'; const options: HTMLReactParserOptions = { replace(domNode) { if (domNode instanceof Element && domNode.attribs) { // ... } }, };
Or use a type assertion:
import { HTMLReactParserOptions, Element } from 'html-react-parser'; const options: HTMLReactParserOptions = { replace(domNode) { if ((domNode as Element).attribs) { // ... } }, };
If you're having issues, take a look at our Create React App example.
replace element and children
Replace the element and its children:
import parse, { domToReact } from 'html-react-parser'; const html = ` <p id="main"> <span class="prettify"> keep me and make me pretty! </span> </p> `; const options = { replace({ attribs, children }) { if (!attribs) { return; } if (attribs.id === 'main') { return <h1 style={{ fontSize: 42 }}>{domToReact(children, options)}</h1>; } if (attribs.class === 'prettify') { return ( <span style={{ color: 'hotpink' }}> {domToReact(children, options)} </span> ); } }, }; parse(html, options);
<h1 style="font-size:42px"> <span style="color:hotpink"> keep me and make me pretty! </span> </h1>
replace element attributes
Convert DOM attributes to React props with attributesToProps:
import parse, { attributesToProps } from 'html-react-parser'; const html = ` <main class="prettify" style="background: #fff; text-align: center;" /> `; const options = { replace(domNode) { if (domNode.attribs && domNode.name === 'main') { const props = attributesToProps(domNode.attribs); return <div {...props} />; } }, }; parse(html, options);
<div class="prettify" style="background:#fff;text-align:center"></div>
replace and remove element
Exclude an element from rendering by replacing it with <React.Fragment>:
parse('<p><br id="remove"></p>', { replace: ({ attribs }) => attribs?.id === 'remove' && <></>, });
<p></p>
transform
The transform option allows you to transform each element individually after it's parsed.
The transform callback's first argument is the React element:
parse('<br>', { transform(reactNode, domNode, index) { // this will wrap every element in a div return <div>{reactNode}</div>; }, });
library
The library option specifies the UI library. The default library is React.
To use Preact:
parse('<br>', { library: require('preact'), });
Or a custom library:
parse('<br>', { library: { cloneElement: () => { /* ... */ }, createElement: () => { /* ... */ }, isValidElement: () => { /* ... */ }, }, });
htmlparser2
Warning
htmlparser2 options do not work on the client-side (browser); they only work on the server-side (Node.js). By overriding the options, it can break universal rendering.
Default htmlparser2 options can be overridden in >=0.12.0.
To enable xmlMode:
parse('<p /><p />', { htmlparser2: { xmlMode: true, }, });
trim
By default, whitespace is preserved:
parse('<br>\n'); // [React.createElement('br'), '\n']
But certain elements like <table> will strip out invalid whitespace:
parse('<table>\n</table>'); // React.createElement('table')
To remove whitespace, enable the trim option:
parse('<br>\n', { trim: true }); // React.createElement('br')
However, intentional whitespace may be stripped out:
parse('<p> </p>', { trim: true }); // React.createElement('p')
trustedTypePolicy
When running in a browser, you can pass a Trusted Types policy so the parser calls trustedTypePolicy.createHTML before assigning content to innerHTML:
parse('<div>Hello</div>', { trustedTypePolicy: window.trustedTypes?.createPolicy('my-policy', { createHTML(input) { // apply sanitization logic here return DOMPurify.sanitize(input); }, }), });
Migration
v6
Changed build target from es5 to es2016.
html-dom-parser has been upgraded to v7 and domhandler has been upgraded to v6.
v5
Migrated to TypeScript. CommonJS imports require the .default key:
const parse = require('html-react-parser').default;
If you're getting the error:
Argument of type 'ChildNode[]' is not assignable to parameter of type 'DOMNode[]'.
Then use type assertion:
domToReact(domNode.children as DOMNode[], options);
See #1126.
v4
htmlparser2 has been upgraded to v9.
v3
domhandler has been upgraded to v5 so some parser options like normalizeWhitespace have been removed.
Also, it's recommended to upgrade to the latest version of TypeScript.
v2
Since v2.0.0, Internet Explorer (IE) is no longer supported.
v1
TypeScript projects will need to update the types in v1.0.0.
For the replace option, you may need to do the following:
import { Element } from 'domhandler/lib/node'; parse('<br class="remove">', { replace(domNode) { if (domNode instanceof Element && domNode.attribs.class === 'remove') { return <></>; } }, });
Since v1.1.1, Internet Explorer 9 (IE9) is no longer supported.
FAQ
Is this XSS safe?
No, this library is not XSS (cross-site scripting) safe (see #94). However, you can mitigate this risk by enforcing a Content Security Policy (CSP) with Trusted Types.
Does invalid HTML get sanitized?
No, this library does not sanitize HTML (see #124, #125, and #141).