html-react-parser
Advanced tools
Comparing version 1.0.0 to 1.1.0
@@ -1,5 +0,12 @@ | ||
# Change Log | ||
# Changelog | ||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. | ||
## [1.1.0](https://github.com/remarkablemark/html-react-parser/compare/v1.0.0...v1.1.0) (2020-12-26) | ||
### Features | ||
* **index:** export `domhandler` node types ([dfa0c19](https://github.com/remarkablemark/html-react-parser/commit/dfa0c1978684f42cdcabd32e95379dfb52ef1d0c)) | ||
# [1.0.0](https://github.com/remarkablemark/html-react-parser/compare/v0.14.3...v1.0.0) (2020-12-14) | ||
@@ -6,0 +13,0 @@ |
@@ -18,2 +18,3 @@ // TypeScript Version: 4.1 | ||
export type HTMLParser2Options = ParserOptions & DomHandlerOptions; | ||
export { Comment, Element, ProcessingInstruction, Text }; | ||
export type DOMNode = Comment | Element | ProcessingInstruction | Text; | ||
@@ -20,0 +21,0 @@ |
{ | ||
"name": "html-react-parser", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "HTML to React parser.", | ||
@@ -44,9 +44,10 @@ "author": "Mark <mark@remarkablemark.org>", | ||
"@rollup/plugin-node-resolve": "^11.0.0", | ||
"@size-limit/preset-big-lib": "^4.9.1", | ||
"@types/react": "^17.0.0", | ||
"@typescript-eslint/parser": "^4.9.0", | ||
"@typescript-eslint/parser": "^4.9.1", | ||
"benchmark": "^2.1.4", | ||
"dtslint": "^4.0.6", | ||
"eslint": "^7.15.0", | ||
"eslint-plugin-prettier": "^3.2.0", | ||
"husky": "^4.3.5", | ||
"eslint-plugin-prettier": "^3.3.0", | ||
"husky": "^4.3.6", | ||
"jest": "^26.6.3", | ||
@@ -61,4 +62,5 @@ "lint-staged": "^10.5.3", | ||
"rollup-plugin-terser": "^7.0.2", | ||
"standard-version": "5", | ||
"typescript": "^4.1.2" | ||
"size-limit": "^4.9.1", | ||
"standard-version": "^9.0.0", | ||
"typescript": "^4.1.3" | ||
}, | ||
@@ -65,0 +67,0 @@ "peerDependencies": { |
196
README.md
@@ -18,12 +18,14 @@ # html-react-parser | ||
It converts an HTML string to one or more [React elements](https://reactjs.org/docs/react-api.html#creating-react-elements). There's also an option to [replace an element](#replacedomnode) with your own. | ||
The parser converts an HTML string to one or more [React elements](https://reactjs.org/docs/react-api.html#creating-react-elements). | ||
Example: | ||
To replace an element with a custom element, check out the [replace option](#replacedomnode). | ||
#### Example | ||
```js | ||
const parse = require('html-react-parser'); | ||
parse('<div>text</div>'); // equivalent to `React.createElement('div', {}, 'text')` | ||
parse('<p>Hello, World!</p>'); // React.createElement('p', {}, 'Hello, World!') | ||
``` | ||
[CodeSandbox](https://codesandbox.io/s/940pov1l4w) | [Repl.it](https://repl.it/@remarkablemark/html-react-parser) | [JSFiddle](https://jsfiddle.net/remarkablemark/7v86d800/) | [Examples](https://github.com/remarkablemark/html-react-parser/tree/master/examples) | ||
[CodeSandbox](https://codesandbox.io/s/940pov1l4w) | [CodeSandbox (TypeScript)](https://codesandbox.io/s/html-react-parser-z0kp6) | [Repl.it](https://repl.it/@remarkablemark/html-react-parser) | [JSFiddle](https://jsfiddle.net/remarkablemark/7v86d800/) | [Examples](https://github.com/remarkablemark/html-react-parser/tree/master/examples) | ||
@@ -35,7 +37,8 @@ <details> | ||
- [Usage](#usage) | ||
- [Options](#options) | ||
- [replace(domNode)](#replacedomnode) | ||
- [replace(domNode)](#replacedomnode) | ||
- [library](#library) | ||
- [htmlparser2](#htmlparser2) | ||
- [trim](#trim) | ||
- [Migration](#migration) | ||
- [v1.0.0](#v100) | ||
- [FAQ](#faq) | ||
@@ -51,3 +54,4 @@ - [Is this XSS safe?](#is-this-xss-safe) | ||
- [Don't change case of tags](#dont-change-case-of-tags) | ||
- [Benchmarks](#benchmarks) | ||
- [TS Error: Property 'attribs' does not exist on type 'DOMNode'](#ts-error-property-attribs-does-not-exist-on-type-domnode) | ||
- [Performance](#performance) | ||
- [Contributors](#contributors) | ||
@@ -81,3 +85,3 @@ - [Code Contributors](#code-contributors) | ||
<!-- HTMLReactParser depends on React --> | ||
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script> | ||
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script> | ||
<script src="https://unpkg.com/html-react-parser@latest/dist/html-react-parser.min.js"></script> | ||
@@ -113,3 +117,3 @@ <script> | ||
Since adjacent elements are parsed as an array, make sure to render them under a parent node: | ||
Make sure to render parsed adjacent elements under a parent element: | ||
@@ -139,13 +143,11 @@ ```jsx | ||
### Options | ||
### replace(domNode) | ||
#### replace(domNode) | ||
The `replace` option allows you to replace an element with another React element. | ||
The `replace` callback allows you to swap an element with another React element. | ||
The `replace` callback's 1st argument is a [domhandler](https://github.com/fb55/domhandler#example) node: | ||
The first argument is an object with the same output as [htmlparser2](https://github.com/fb55/htmlparser2/tree/v3.10.1)'s [domhandler](https://github.com/fb55/domhandler#example): | ||
```js | ||
parse('<br>', { | ||
replace: function (domNode) { | ||
replace: domNode => { | ||
console.dir(domNode, { depth: null }); | ||
@@ -159,18 +161,21 @@ } | ||
```js | ||
{ type: 'tag', | ||
Element { | ||
parent: null, | ||
prev: null, | ||
next: null, | ||
startIndex: null, | ||
endIndex: null, | ||
children: [], | ||
name: 'br', | ||
attribs: {}, | ||
children: [], | ||
next: null, | ||
prev: null, | ||
parent: null } | ||
attribs: {} | ||
} | ||
``` | ||
The element is replaced only if a _valid_ React element is returned: | ||
The element is replaced if a **valid** React element is returned: | ||
```js | ||
```jsx | ||
parse('<p id="replace">text</p>', { | ||
replace: domNode => { | ||
if (domNode.attribs && domNode.attribs.id === 'replace') { | ||
return React.createElement('span', {}, 'replaced'); | ||
return <span>replaced</span>; | ||
} | ||
@@ -181,7 +186,19 @@ } | ||
Here's an [example](https://repl.it/@remarkablemark/html-react-parser-replace-example) that modifies an element but keeps the children: | ||
For TypeScript projects, check that `domNode` is an instance of domhandler's `Element`: | ||
```tsx | ||
import parse, { Element } from 'html-react-parser'; | ||
parse('<p id="replace">text</p>', { | ||
replace: domNode => { | ||
if (domNode instanceof Element && domNode.attribs.id === 'replace') { | ||
return <span>replaced</span>; | ||
} | ||
} | ||
}); | ||
``` | ||
The following [example](https://repl.it/@remarkablemark/html-react-parser-replace-example) modifies the element along with its children: | ||
```jsx | ||
import React from 'react'; | ||
import { renderToStaticMarkup } from 'react-dom/server'; | ||
import parse, { domToReact } from 'html-react-parser'; | ||
@@ -199,3 +216,5 @@ | ||
replace: ({ attribs, children }) => { | ||
if (!attribs) return; | ||
if (!attribs) { | ||
return; | ||
} | ||
@@ -216,46 +235,65 @@ if (attribs.id === 'main') { | ||
console.log(renderToStaticMarkup(parse(html, options))); | ||
parse(html, options); | ||
``` | ||
Use the exported attributesToProps method to convert DOM attributes to React Props: | ||
HTML output: | ||
<!-- prettier-ignore-start --> | ||
```html | ||
<h1 style="font-size:42px"> | ||
<span style="color:hotpink"> | ||
keep me and make me pretty! | ||
</span> | ||
</h1> | ||
``` | ||
<!-- prettier-ignore-end --> | ||
Convert DOM attributes to React props with `attributesToProps`: | ||
```jsx | ||
import React from 'react'; | ||
import parse, { attributesToProps } from 'html-react-parser'; | ||
const html = ` | ||
<hr class="prettify" style="background:#fff;text-align:center" /> | ||
<main class="prettify" style="background: #fff; text-align: center;" /> | ||
`; | ||
const options = { | ||
replace: node => { | ||
if (node.attribs && node.name === 'hr') { | ||
const props = attributesToProps(node.attribs); | ||
return <hr {...props} />; | ||
replace: domNode => { | ||
if (domNode.attribs && domNode.name === 'main') { | ||
const props = attributesToProps(domNode.attribs); | ||
return <div {...props} />; | ||
} | ||
} | ||
}; | ||
parse(html, options); | ||
``` | ||
Output: | ||
HTML output: | ||
```html | ||
<h1 style="font-size:42px"> | ||
<span style="color:hotpink"> keep me and make me pretty! </span> | ||
</h1> | ||
<div class="prettify" style="background:#fff;text-align:center"></div> | ||
``` | ||
Here's an [example](https://repl.it/@remarkablemark/html-react-parser-56) that excludes an element: | ||
[Exclude](https://repl.it/@remarkablemark/html-react-parser-56) an element from rendering by replacing it with `<React.Fragment>`: | ||
```jsx | ||
parse('<p><br id="remove"></p>', { | ||
replace: ({ attribs }) => attribs && attribs.id === 'remove' && <Fragment /> | ||
replace: ({ attribs }) => attribs && attribs.id === 'remove' && <></> | ||
}); | ||
``` | ||
HTML output: | ||
```html | ||
<p></p> | ||
``` | ||
### library | ||
The `library` option allows you to specify which component library is used to create elements. React is used by default if this option is not specified. | ||
This option specifies the library that creates elements. The default library is **React**. | ||
Here's an example showing how to use Preact: | ||
To use Preact: | ||
@@ -268,3 +306,3 @@ ```js | ||
Or, using a custom library: | ||
Or a custom library: | ||
@@ -289,3 +327,3 @@ ```js | ||
The default options passed to [htmlparser2](https://github.com/fb55/htmlparser2/tree/v3.10.1) are: | ||
The default [htmlparser2 options](https://github.com/fb55/htmlparser2/wiki/Parser-options) are: | ||
@@ -299,5 +337,5 @@ ```js | ||
Since [v0.12.0](https://github.com/remarkablemark/html-react-parser/tree/v0.12.0), you can override the default options by passing [htmlparser2 options](https://github.com/fb55/htmlparser2/wiki/Parser-options). | ||
Since [v0.12.0](https://github.com/remarkablemark/html-react-parser/tree/v0.12.0), the htmlparser2 options can be overridden. | ||
Here's an example in which [`decodeEntities`](https://github.com/fb55/htmlparser2/wiki/Parser-options#option-decodeentities) and [`xmlMode`](https://github.com/fb55/htmlparser2/wiki/Parser-options#option-xmlmode) are enabled: | ||
The following example enables [`decodeEntities`](https://github.com/fb55/htmlparser2/wiki/Parser-options#option-decodeentities) and [`xmlMode`](https://github.com/fb55/htmlparser2/wiki/Parser-options#option-xmlmode): | ||
@@ -313,3 +351,3 @@ ```js | ||
> **Warning**: `htmlparser2` is only applicable on the _server-side_ (Node.js) and not applicable on the _client-side_ (browser). By overriding `htmlparser2` options, there's a chance that universal rendering breaks. Do this at your own _risk_. | ||
> **WARNING**: `htmlparser2` options do not apply on the _client-side_ (browser). The options only apply on the _server-side_ (Node.js). By overriding `htmlparser2` options, universal rendering can break. Do this at your own risk. | ||
@@ -324,3 +362,3 @@ ### trim | ||
By enabling the `trim` option, whitespace text nodes will be skipped: | ||
Enable the `trim` option to remove whitespace: | ||
@@ -331,3 +369,3 @@ ```js | ||
This addresses the warning: | ||
This fixes the warning: | ||
@@ -338,3 +376,3 @@ ``` | ||
However, this option may strip out intentional whitespace: | ||
However, intentional whitespace may be stripped out: | ||
@@ -345,29 +383,49 @@ ```js | ||
## Migration | ||
### v1.0.0 | ||
TypeScript projects will need to check the types in [v1.0.0](https://github.com/remarkablemark/html-react-parser/releases/tag/v1.0.0). | ||
For `replace` option: | ||
```tsx | ||
import parse, { Element } from 'html-react-parser'; | ||
parse('<br class="remove">', { | ||
replace: domNode => { | ||
if (domNode instanceof Element && domNode.attribs.class === 'remove') { | ||
return <></>; | ||
} | ||
} | ||
}); | ||
``` | ||
## FAQ | ||
#### Is this XSS safe? | ||
### Is this XSS safe? | ||
No, 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). | ||
#### Does invalid HTML get sanitized? | ||
### Does invalid HTML get sanitized? | ||
No, 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). | ||
#### Are `<script>` tags parsed? | ||
### Are `<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](https://github.com/remarkablemark/html-react-parser/issues/98). | ||
#### Attributes aren't getting called | ||
### Attributes aren't getting called | ||
The 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). | ||
#### Parser throws an error | ||
### Parser throws an error | ||
If the parser throws an erorr, check if your arguments are valid. See ["Does invalid HTML get sanitized?"](#does-invalid-html-get-sanitized). | ||
#### Is SSR supported? | ||
### Is SSR supported? | ||
Yes, server-side rendering on Node.js is supported by this library. See [demo](https://repl.it/@remarkablemark/html-react-parser-SSR). | ||
#### Elements aren't nested correctly | ||
### Elements aren't nested correctly | ||
@@ -382,7 +440,7 @@ If 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: | ||
#### Warning: validateDOMNesting(...): Whitespace text nodes cannot appear as a child of table | ||
### Warning: validateDOMNesting(...): Whitespace text nodes cannot appear as a child of table | ||
Enable the [trim](#trim) option. See [#155](https://github.com/remarkablemark/html-react-parser/issues/155). | ||
#### Don't change case of tags | ||
### Don't change case of tags | ||
@@ -408,4 +466,10 @@ Tags are lowercased by default. To prevent that from happening, pass the [htmlparser2 option](#htmlparser2): | ||
## Benchmarks | ||
### TS Error: Property 'attribs' does not exist on type 'DOMNode' | ||
The TypeScript error happens because `DOMNode` needs be an instance of domhandler's `Element`. See [migration](#migration) or [#199](https://github.com/remarkablemark/html-react-parser/issues/199). | ||
## Performance | ||
Run benchmark: | ||
```sh | ||
@@ -415,3 +479,3 @@ $ npm run test:benchmark | ||
Here's an example output of the benchmarks run on a MacBook Pro 2017: | ||
Output of benchmark run on MacBook Pro 2017: | ||
@@ -424,2 +488,8 @@ ``` | ||
Run [Size Limit](https://github.com/ai/size-limit): | ||
```sh | ||
$ npx size-limit | ||
``` | ||
## Contributors | ||
@@ -426,0 +496,0 @@ |
313174
2269
517
24