Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
html-react-parser
Advanced tools
The html-react-parser package is designed to convert HTML strings into React components. This is particularly useful when you need to dynamically render HTML content in a React application, such as content fetched from a CMS or API that returns HTML. It allows for custom handling of elements, attributes, and can work with server-side rendering.
Parsing HTML strings to React Elements
This feature allows you to convert a string of HTML into React elements that can be rendered inside a React component.
import parse from 'html-react-parser';
const html = '<div>Hello World</div>';
const reactElement = parse(html);
Replacing or modifying elements during parsing
This feature allows you to define a 'replace' function in the options object that can modify or replace elements during the parsing process.
import parse, { domToReact } from 'html-react-parser';
const html = '<p id="replace">Replace me</p>';
const options = {
replace: ({ attribs, children }) => {
if (attribs && attribs.id === 'replace') {
return <span>{domToReact(children)}</span>;
}
}
};
const reactElement = parse(html, options);
Preserving custom attributes and event handlers
This feature allows you to preserve custom attributes and potentially event handlers when parsing HTML to React elements.
import parse from 'html-react-parser';
const html = '<div onclick="handleClick()">Click me</div>';
const reactElement = parse(html, {
preserveAttributes: ['onclick']
});
react-html-parser is similar to html-react-parser in that it converts HTML strings into React components. However, it may differ in the specifics of its API and the options it provides for customization during the parsing process.
dangerously-set-html-content provides a component that can be used to set raw HTML content. It is similar to using the dangerouslySetInnerHTML prop in React but encapsulated in a component for easier use. It does not offer the same level of customization or parsing capabilities as html-react-parser.
sanitize-html-react is designed to sanitize HTML strings before they are rendered to prevent XSS attacks. It can be used in conjunction with html-react-parser to first sanitize the HTML string and then parse it into React components. It focuses more on security rather than parsing.
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.
import parse from 'html-react-parser';
parse('<p>Hello, World!</p>'); // React.createElement('p', {}, 'Hello, World!')
Replit | JSFiddle | StackBlitz | TypeScript | Examples
<script>
tags parsed?trim
for certain elements?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>
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;">',
);
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.
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 the element and its children (see demo):
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>
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>
Exclude an element from rendering by replacing it with <React.Fragment>
:
parse('<p><br id="remove"></p>', {
replace: ({ attribs }) => attribs?.id === 'remove' && <></>,
});
<p></p>
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>;
},
});
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: () => {
/* ... */
},
},
});
[!WARNING]
htmlparser2
options don't 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,
},
});
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')
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.
htmlparser2 has been upgraded to v9.
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.
Since v2.0.0, Internet Explorer (IE) is no longer supported.
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.
No, this library is not XSS (cross-site scripting) safe. See #94.
No, this library does not sanitize HTML. See #124, #125, and #141.
<script>
tags parsed?Although <script>
tags and their contents are rendered on the server-side, they're not evaluated on the client-side. See #98.
The reason why your HTML attributes aren't getting called is because inline event handlers (e.g., onclick
) are parsed as a string rather than a function. See #73.
If the parser throws an error, check if your arguments are valid. See "Does invalid HTML get sanitized?".
Yes, server-side rendering on Node.js is supported by this library. See demo.
If your elements are nested incorrectly, check to make sure your HTML markup is valid. The HTML to DOM parsing will be affected if you're using self-closing syntax (/>
) on non-void elements:
parse('<div /><div />'); // returns single element instead of array of elements
See #158.
Tags are lowercased by default. To prevent that from happening, pass the htmlparser2 option:
const options = {
htmlparser2: {
lowerCaseTags: false,
},
};
parse('<CustomElement>', options); // React.createElement('CustomElement')
[!WARNING] By preserving case-sensitivity of the tags, you may get rendering warnings like:
Warning: <CustomElement> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.
The TypeScript error occurs because DOMNode
needs to be an instance of domhandler's Element
. See migration or #199.
trim
for certain elements?Yes, you can enable or disable trim
for certain elements using the replace
option. See #205.
If you see the Webpack build warning:
export 'default' (imported as 'parse') was not found in 'html-react-parser'
Then update your Webpack config to:
// webpack.config.js
module.exports = {
// ...
resolve: {
mainFields: ['browser', 'main', 'module'],
},
};
If you see the TypeScript error:
node_modules/htmlparser2/lib/index.d.ts:2:23 - error TS1005: ',' expected.
2 export { Parser, type ParserOptions };
~~~~~~~~~~~~~
Then upgrade to the latest version of typescript. See #748.
Run benchmark:
npm run benchmark
Output of benchmark run on MacBook Pro 2021:
html-to-react - Single x 1,018,239 ops/sec ±0.43% (94 runs sampled)
html-to-react - Multiple x 380,037 ops/sec ±0.61% (97 runs sampled)
html-to-react - Complex x 35,091 ops/sec ±0.50% (96 runs sampled)
Run Size Limit:
npx size-limit
This project exists thanks to all the people who contribute. [Contribute].
Become a financial contributor and help us sustain our community. [Contribute]
Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]
FAQs
HTML to React parser.
The npm package html-react-parser receives a total of 1,281,123 weekly downloads. As such, html-react-parser popularity was classified as popular.
We found that html-react-parser demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.