html-to-react

A lightweight library that converts raw HTML to a React DOM structure.

Github星跟蹤圖

html-to-react

Greenkeeper badge
Build Status
npm version
Dependency Status
Coverage Status
npm

A lightweight library that converts raw HTML to a React DOM structure.

Why?

I had a scenario where an HTML template was generated by a different team, yet I wanted to leverage
React for the parts I did have control over. The template basically contains something like:

<div class="row">
  <div class="col-sm-6">
    <div data-report-id="report-1">
      <!-- A React component for report-1 -->
    </div>
  </div>
  <div class="col-sm-6">
    <div data-report-id="report-2">
      <!-- A React component for report-2 -->
    </div>
  </div>
</div>

I had to replace each <div> that contains a data-report-id attribute with an actual report,
which was nothing more than a React component.

Simply replacing the <div> elements with a React component would end up with multiple top-level
React components that have no common parent.

The html-to-react module solves this problem by parsing each DOM element and converting it to a
React tree with one single parent.

Installation

$ npm install --save html-to-react

Examples

Simple

The following example parses each node and its attributes and returns a tree of React elements.

var ReactDOMServer = require('react-dom/server');
var HtmlToReactParser = require('html-to-react').Parser;

var htmlInput = '<div><h1>Title</h1><p>A paragraph</p></div>';
var htmlToReactParser = new HtmlToReactParser();
var reactElement = htmlToReactParser.parse(htmlInput);
var reactHtml = ReactDOMServer.renderToStaticMarkup(reactElement);

assert.equal(reactHtml, htmlInput); // true

With Custom Processing Instructions

If certain DOM nodes require specific processing, for example if you want to capitalize each
<h1> tag, the following example demonstrates this:

var ReactDOMServer = require('react-dom/server');
var HtmlToReact = require('html-to-react');
var HtmlToReactParser = require('html-to-react').Parser;

var htmlInput = '<div><h1>Title</h1><p>Paragraph</p><h1>Another title</h1></div>';
var htmlExpected = '<div><h1>TITLE</h1><p>Paragraph</p><h1>ANOTHER TITLE</h1></div>';

var isValidNode = function () {
  return true;
};

// Order matters. Instructions are processed in the order they're defined
var processNodeDefinitions = new HtmlToReact.ProcessNodeDefinitions(React);
var processingInstructions = [
  {
    // Custom <h1> processing
    shouldProcessNode: function (node) {
      return node.parent && node.parent.name && node.parent.name === 'h1';
    },
    processNode: function (node, children) {
      return node.data.toUpperCase();
    }
  },
  {
    // Anything else
    shouldProcessNode: function (node) {
      return true;
    },
    processNode: processNodeDefinitions.processDefaultNode
  }
];
var htmlToReactParser = new HtmlToReactParser();
var reactComponent = htmlToReactParser.parseWithInstructions(htmlInput, isValidNode,
  processingInstructions);
var reactHtml = ReactDOMServer.renderToStaticMarkup(reactComponent);
assert.equal(reactHtml, htmlExpected);

Replace the Children of an Element

There may be a situation where you want to replace the children of an element with a React
component. This is beneficial if you want to:

  • a) Preserve the containing element
  • b) Not rely on any child node to insert your React component

Example

Below is a simple template that could get loaded via ajax into your application

Before
<div class="row">
  <div class="col-sm-6">
    <div data-container="wysiwyg">
      <h1>Sample Heading</h1>
      <p>Sample Text</p>
    </div>
  </div>
</div>
After

You may want to extract the inner html from the data-container attribute, store it and then pass
it as a prop to your injected RichTextEditor.

<div class="row">
  <div class="col-sm-6">
    <div data-container="wysiwyg">
      <RichTextEditor html={"<h1>Sample heading</h1><p>Sample Text</p>"} />
    </div>
  </div>
</div>

Setup

In your instructions object, you must specify replaceChildren: true.

var React = require('react');
var HtmlToReact = require('html-to-react');
var HtmlToReactParser = require('html-to-react').Parser;

var htmlToReactParser = new HtmlToReactParser();
var htmlInput = '<div><div data-test="foo"><p>Text</p><p>Text</p></div></div>';
var htmlExpected = '<div><div data-test="foo"><h1>Heading</h1></div></div>';

var isValidNode = function () {
  return true;
};

var processNodeDefinitions = new HtmlToReact.ProcessNodeDefinitions(React);

// Order matters. Instructions are processed in
// the order they're defined
var processingInstructions = [
  {
    // This is REQUIRED, it tells the parser
    // that we want to insert our React
    // component as a child
    replaceChildren: true,
    shouldProcessNode: function (node) {
      return node.attribs && node.attribs['data-test'] === 'foo';
    },
    processNode: function (node, children, index) {
      return React.createElement('h1', {key: index,}, 'Heading');
    }
  },
  {
    // Anything else
    shouldProcessNode: function (node) {
      return true;
    },
    processNode: processNodeDefinitions.processDefaultNode,
  },
];

var reactComponent = htmlToReactParser.parseWithInstructions(
  htmlInput, isValidNode, processingInstructions);
var reactHtml = ReactDOMServer.renderToStaticMarkup(
  reactComponent);
assert.equal(reactHtml, htmlExpected);

With Preprocessing Instructions

There may be situations where you want to preprocess nodes before rendering them, analogously
to the custom processing instructions functionality. The rationale for supporting preprocessing
hooks is generally that you might want to apply more general processing to nodes, before
applying custom processing hooks to filtered sets of nodes. You could accomplish the same by
calling common functions from your custom processing hooks, but the preprocessing hooks
API makes it more convenient.

Example

Below is a simple template in which you may want to replace div IDs, via a preprocessing hook:

<div class="row">
  <div id="first" data-process="shared">
    <p>Sample For First</p>
  </div>
  <div id="second" data-process="shared">
    <p>Sample For Second</p>
  </div>
</div>

We want to process the above HTML into the following:

<div class="row">
  <h1 id="preprocessed-first">First</h1>
  <h2 id="preprocessed-second">Second</h2>
</div>

We can accomplish that with the following script, using a combination of preprocessing and
custom processing instructions:

var React = require('react');
var HtmlToReact = require('html-to-react');
var HtmlToReactParser = require('html-to-react').Parser;

var htmlToReactParser = new HtmlToReactParser();
var htmlInput = '<div class="row">' +
  '<div id="first" data-process="shared">' +
    '<p>Sample For First</p>' +
  '</div>' +
  '<div id="second" data-process="shared">' +
    '<p>Sample For Second</p>' +
  '</div>' +
'</div>';

var htmlExpected = '<div class="row">' +
  '<h1 id="preprocessed-first">First</h1>' +
  '<h2 id="preprocessed-second">Second</h2>' +
'</div>';

var isValidNode = function () {
  return true;
};

var preprocessingInstructions = [
  {
    shouldPreprocessNode: function (node) {
      return node.attribs && node.attribs['data-process'] === 'shared';
    },
    preprocessNode: function (node) {
      node.attribs = {id: `preprocessed-${node.attribs.id}`,};
    },
  }
];
var processNodeDefinitions = new HtmlToReact.ProcessNodeDefinitions(React);
var processingInstructions = [
  {
    shouldProcessNode: function (node) {
      return node.attribs && node.attribs.id === 'preprocessed-first';
    },
    processNode: function(node, children, index) {
      return React.createElement('h1', {key: index, id: node.attribs.id,}, 'First');
    },
  },
  {
    shouldProcessNode: function (node) {
      return node.attribs && node.attribs.id === 'preprocessed-second';
    },
    processNode: function (node, children, index) {
      return React.createElement('h2', {key: index, id: node.attribs.id,}, 'Second');
    },
  },
  {
    shouldProcessNode: function (node) {
      return true;
    },
    processNode: processNodeDefinitions.processDefaultNode,
  },
];

var reactComponent = parser.parseWithInstructions(htmlInput, isValidNode, processingInstructions,
  preprocessingInstructions);
var reactHtml = ReactDOMServer.renderToStaticMarkup(reactComponent);
assert.equal(reactHtml, htmlExpected);

Tests & Coverage

Test locally: $ npm test

Test with coverage and report coverage to Coveralls: $ npm run test-coverage

Test with coverage and open HTML report: $ npm run test-html-coverage

主要指標

概覽
名稱與所有者aknuds1/html-to-react
主編程語言TypeScript
編程語言JavaScript (語言數: 3)
平台
許可證MIT License
所有者活动
創建於2015-12-11 19:33:51
推送於2025-07-14 02:52:25
最后一次提交2025-07-14 02:52:24
發布數40
最新版本名稱v1.7.0 (發布於 2023-10-04 10:27:39)
第一版名稱v0.0.2 (發布於 2015-06-20 13:22:56)
用户参与
星數794
關注者數8
派生數81
提交數834
已啟用問題?
問題數85
打開的問題數14
拉請求數187
打開的拉請求數0
關閉的拉請求數42
项目设置
已啟用Wiki?
已存檔?
是復刻?
已鎖定?
是鏡像?
是私有?