HTML to React parser that works on both server-side and client-side environments
npx @tessl/cli install tessl/npm-html-react-parser@5.2.0HTML React Parser is a robust TypeScript library that converts HTML strings into React elements. It works seamlessly in both server-side (Node.js) and client-side (browser) environments, providing comprehensive HTML parsing with advanced customization options.
npm install html-react-parserimport parse from "html-react-parser";
import type { HTMLReactParserOptions } from "html-react-parser";For additional utilities:
import {
attributesToProps,
domToReact,
htmlToDOM,
Element,
Text,
Comment
} from "html-react-parser";CommonJS:
const parse = require("html-react-parser").default;
const { attributesToProps, domToReact } = require("html-react-parser");UMD (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>
// Available as window.HTMLReactParser
const parsed = window.HTMLReactParser('<p>Hello from CDN!</p>');
</script>import parse from "html-react-parser";
// Simple HTML parsing
const element = parse('<p>Hello, World!</p>');
// Returns: React.createElement('p', {}, 'Hello, World!')
// Complex HTML with nested elements
const complexHtml = `
<div class="container">
<h1>Title</h1>
<p style="color: red;">Red text</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
`;
const result = parse(complexHtml);
// With options
const customParsed = parse('<div data-id="123">Content</div>', {
replace: (domNode) => {
if (domNode.type === 'tag' && domNode.name === 'div') {
return <span>Replaced content</span>;
}
}
});HTML React Parser is built around several key components:
HTMLReactParserhtmlToDOMdomToReactattributesToPropsCore functionality for converting HTML strings to React elements with comprehensive options support.
/**
* Converts HTML string to React elements.
* @param html - HTML string to parse
* @param options - Optional parser configuration
* @returns React element(s), empty array, or string
* @throws TypeError if first argument is not a string
*/
function HTMLReactParser(
html: string,
options?: HTMLReactParserOptions
): string | JSX.Element | JSX.Element[];Usage Examples:
import parse from "html-react-parser";
// Basic parsing
parse('<p>Hello</p>'); // React element
parse('Just text'); // String
parse(''); // Empty array []
// Multiple elements
parse('<p>First</p><p>Second</p>'); // Array of React elements
// Self-closing tags
parse('<img src="image.jpg" alt="Photo" />'); // React element with props
// Nested elements with attributes
parse(`
<div className="wrapper" data-testid="container">
<h1 style="font-size: 24px;">Title</h1>
<button onClick="handleClick()">Click me</button>
</div>
`);Low-level function for converting DOM nodes directly to React elements.
/**
* Converts DOM nodes to JSX element(s).
* @param nodes - Array of DOM nodes to convert
* @param options - Parser configuration with default empty object
* @returns String or JSX element(s)
*/
function domToReact(
nodes: DOMNode[],
options: HTMLReactParserOptions = {}
): string | JSX.Element | JSX.Element[];Utility function that converts HTML strings to DOM node structures.
/**
* Converts HTML string to DOM nodes using html-dom-parser
* @param html - HTML string to parse
* @param options - htmlparser2 parsing options
* @returns Array of DOM nodes
*/
function htmlToDOM(html: string, options?: any): DOMNode[];Converts HTML/SVG DOM attributes to React-compatible props with proper naming conventions.
/**
* Converts HTML/SVG DOM attributes to React props.
* @param attributes - HTML/SVG DOM attributes object
* @param nodeName - DOM node name for context-specific processing
* @returns React props object
*/
function attributesToProps(
attributes?: Attributes,
nodeName?: string
): Props;
type Attributes = Record<PropertyKey, string>;
interface Props extends Record<PropertyKey, string | boolean> {
dangerouslySetInnerHTML?: {
__html: string;
};
key?: string | number;
style?: Record<PropertyKey, string>;
}Usage Examples:
import { attributesToProps } from "html-react-parser";
// HTML attributes to React props
const htmlAttrs = { 'class': 'btn', 'data-id': '123', 'for': 'input1' };
const reactProps = attributesToProps(htmlAttrs);
// Result: { className: 'btn', 'data-id': '123', htmlFor: 'input1' }
// Input element handling (controlled vs uncontrolled)
const inputAttrs = { type: 'text', value: 'hello' };
const inputProps = attributesToProps(inputAttrs, 'input');
// Result: { type: 'text', defaultValue: 'hello' } // Converts to uncontrolled
// Style attribute processing
const styledAttrs = { style: 'color: red; font-size: 16px;' };
const styledProps = attributesToProps(styledAttrs);
// Result: { style: { color: 'red', fontSize: '16px' } }Advanced customization through the replace option for targeted element modification.
type ReplaceFunction = (
domNode: DOMNode,
index: number
) => JSX.Element | string | null | boolean | object | void;Usage Examples:
import parse from "html-react-parser";
// Replace specific elements
const html = '<p>Text</p><button>Click</button>';
const result = parse(html, {
replace: (domNode) => {
if (domNode.type === 'tag' && domNode.name === 'button') {
return <button className="custom-btn">{domNode.children[0].data}</button>;
}
}
});
// Conditional element replacement
parse('<div class="old">Content</div>', {
replace: (domNode) => {
if (domNode.type === 'tag' && domNode.attribs?.class === 'old') {
return <div className="new">Updated content</div>;
}
}
});
// Remove elements by returning null
parse('<script>alert("xss")</script><p>Safe content</p>', {
replace: (domNode) => {
if (domNode.type === 'tag' && domNode.name === 'script') {
return null; // Remove script tags
}
}
});Post-processing transformation of React nodes after initial creation.
type TransformFunction = (
reactNode: ReactNode,
domNode: DOMNode,
index: number
) => JSX.Element | string | null | void;Usage Examples:
import parse from "html-react-parser";
import React from "react";
// Add props to all elements
parse('<div><p>Text</p></div>', {
transform: (reactNode, domNode, index) => {
if (reactNode.type) {
return React.cloneElement(reactNode, {
...reactNode.props,
'data-index': index
});
}
return reactNode;
}
});
// Wrap text nodes
parse('<p>Hello world</p>', {
transform: (reactNode, domNode) => {
if (typeof reactNode === 'string') {
return <span className="text-wrapper">{reactNode}</span>;
}
return reactNode;
}
});Integration with alternative React-compatible libraries like Preact.
interface LibraryConfig {
cloneElement: (
element: JSX.Element,
props?: object,
...children: any[]
) => JSX.Element;
createElement: (
type: any,
props?: object,
...children: any[]
) => JSX.Element;
isValidElement: (element: any) => boolean;
[key: string]: any;
}Usage Examples:
import { h, cloneElement, isValidElement } from "preact";
import parse from "html-react-parser";
// Use with Preact
const preactResult = parse('<div>Hello Preact</div>', {
library: {
createElement: h,
cloneElement: cloneElement,
isValidElement: isValidElement
}
});interface HTMLReactParserOptions {
/** htmlparser2 and domhandler configuration options */
htmlparser2?: ParserOptions & DomHandlerOptions;
/** Custom React-compatible library methods */
library?: LibraryConfig;
/** Function to replace DOM elements with custom React elements */
replace?: ReplaceFunction;
/** Function to transform React nodes after creation */
transform?: TransformFunction;
/** Whether to trim whitespace text nodes */
trim?: boolean;
}Re-exported DOM node classes from the domhandler library for type checking and instanceof operations.
/**
* DOM element node class
*/
class Element {
type: 'tag' | 'script' | 'style';
name: string;
attribs: Record<string, string>;
children: DOMNode[];
parent?: DOMNode;
}
/**
* DOM text node class
*/
class Text {
type: 'text';
data: string;
parent?: DOMNode;
}
/**
* DOM comment node class
*/
class Comment {
type: 'comment';
data: string;
parent?: DOMNode;
}
/**
* DOM processing instruction node class
*/
class ProcessingInstruction {
type: 'directive';
name: string;
data: string;
parent?: DOMNode;
}
/**
* Union type for all DOM node types
*/
type DOMNode = Element | Text | Comment | ProcessingInstruction;Usage Examples:
import parse, { Element, Text } from "html-react-parser";
parse('<div>Hello</div>', {
replace: (domNode) => {
if (domNode instanceof Element && domNode.name === 'div') {
return <section>{domNode.children}</section>;
}
if (domNode instanceof Text && domNode.data.includes('Hello')) {
return <strong>{domNode.data}</strong>;
}
}
});Fine-tune the underlying HTML parsing behavior through htmlparser2 configuration.
⚠️ Warning: htmlparser2 options only work on the server-side (Node.js) and do not work on the client-side (browser). Using these options can break universal rendering.
interface ParserOptions {
/** Decode HTML entities in attribute values and text content */
decodeEntities?: boolean;
/** Convert tag names to lowercase */
lowerCaseTags?: boolean;
/** Convert attribute names to lowercase */
lowerCaseAttributeNames?: boolean;
/** Recognize self-closing tags */
recognizeSelfClosing?: boolean;
/** Enable XML mode with stricter parsing rules */
xmlMode?: boolean;
/** Additional htmlparser2 configuration options */
[key: string]: any;
}Usage Examples:
import parse from "html-react-parser";
// Custom parsing options
parse('<DIV CLASS="Test">Content</DIV>', {
htmlparser2: {
lowerCaseTags: false,
lowerCaseAttributeNames: false
}
});
// Handle XML-style self-closing tags
parse('<custom-element attr="value"/>', {
htmlparser2: {
recognizeSelfClosing: true
}
});The parser throws specific errors for invalid inputs and provides helpful error messages.
import parse from "html-react-parser";
// TypeError for non-string inputs
try {
parse(null as any); // TypeError: First argument must be a string
parse(123 as any); // TypeError: First argument must be a string
parse({} as any); // TypeError: First argument must be a string
} catch (error) {
console.error(error.message); // "First argument must be a string"
}
// Empty strings return empty arrays (not errors)
const empty = parse(''); // []
// Invalid HTML is parsed as best as possible (no errors thrown)
const malformed = parse('<div><p>Unclosed div'); // Still produces React elements
const selfClosing = parse('<div/>'); // Parsed correctly
const mismatched = parse('<div></span>'); // Best-effort parsing
// Browser/server compatibility errors
try {
parse('<div>content</div>', {
htmlparser2: {
xmlMode: true // This works on server but may cause issues on client
}
});
} catch (error) {
// Handle potential universal rendering issues
console.warn('htmlparser2 options may not work on client-side');
}