{"id":13439124,"url":"https://github.com/aknuds1/html-to-react","last_synced_at":"2025-10-03T15:31:06.556Z","repository":{"id":38375708,"uuid":"47846965","full_name":"aknuds1/html-to-react","owner":"aknuds1","description":"A lightweight library that converts raw HTML to a React DOM structure.","archived":false,"fork":true,"pushed_at":"2024-04-15T15:14:33.000Z","size":1527,"stargazers_count":779,"open_issues_count":13,"forks_count":80,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-04-15T22:58:34.176Z","etag":null,"topics":["conversion","html","javascript","javascript-library","npm-package","react"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"mikenikles/html-to-react","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aknuds1.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2015-12-11T19:33:51.000Z","updated_at":"2024-04-15T20:31:37.000Z","dependencies_parsed_at":"2023-02-15T17:00:58.175Z","dependency_job_id":null,"html_url":"https://github.com/aknuds1/html-to-react","commit_stats":{"total_commits":387,"total_committers":36,"mean_commits":10.75,"dds":"0.30490956072351416","last_synced_commit":"e8f6ced8113d289ae06d2dc0aae6b818fe8f5993"},"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aknuds1%2Fhtml-to-react","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aknuds1%2Fhtml-to-react/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aknuds1%2Fhtml-to-react/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aknuds1%2Fhtml-to-react/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aknuds1","download_url":"https://codeload.github.com/aknuds1/html-to-react/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235146599,"owners_count":18943286,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["conversion","html","javascript","javascript-library","npm-package","react"],"created_at":"2024-07-31T03:01:11.351Z","updated_at":"2025-10-03T15:31:01.256Z","avatar_url":"https://github.com/aknuds1.png","language":"TypeScript","readme":"# html-to-react\n\n[![Greenkeeper badge](https://badges.greenkeeper.io/aknuds1/html-to-react.svg)](https://greenkeeper.io/)\n[![Build Status](https://travis-ci.org/aknuds1/html-to-react.svg?branch=master)](https://travis-ci.org/aknuds1/html-to-react)\n[![npm version](https://badge.fury.io/js/html-to-react.svg)](http://badge.fury.io/js/html-to-react)\n[![Dependency Status](https://david-dm.org/aknuds1/html-to-react.svg)](https://david-dm.org/aknuds1/html-to-react)\n[![Coverage Status](https://coveralls.io/repos/aknuds1/html-to-react/badge.svg?branch=master)](https://coveralls.io/r/aknuds1/html-to-react?branch=master)\n[![npm](https://img.shields.io/npm/dm/html-to-react.svg?maxAge=2592000)](https://www.npmjs.com/package/html-to-react)\n\nA lightweight library that converts raw HTML to a React DOM structure.\n\n## Why?\nI had a scenario where an HTML template was generated by a different team, yet I wanted to leverage\nReact for the parts I did have control over. The template basically contains something like:\n\n```html\n\u003cdiv class=\"row\"\u003e\n  \u003cdiv class=\"col-sm-6\"\u003e\n    \u003cdiv data-report-id=\"report-1\"\u003e\n      \u003c!-- A React component for report-1 --\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"col-sm-6\"\u003e\n    \u003cdiv data-report-id=\"report-2\"\u003e\n      \u003c!-- A React component for report-2 --\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\nI had to replace each `\u003cdiv\u003e` that contains a `data-report-id` attribute with an actual report,\nwhich was nothing more than a React component.\n\nSimply replacing the `\u003cdiv\u003e` elements with a React component would end up with multiple top-level\nReact components that have no common parent.\n\nThe **html-to-react** module solves this problem by parsing each DOM element and converting it to a\nReact tree with one single parent.\n\n## Installation\n\n`$ npm install --save html-to-react`\n\n## Examples\n\n### Simple\n\nThe following example parses each node and its attributes and returns a tree of React elements.\n\n```javascript\nconst ReactDOMServer = require('react-dom/server');\nconst HtmlToReactParser = require('html-to-react').Parser;\n\nconst htmlInput = '\u003cdiv\u003e\u003ch1\u003eTitle\u003c/h1\u003e\u003cp\u003eA paragraph\u003c/p\u003e\u003c/div\u003e';\nconst htmlToReactParser = new HtmlToReactParser();\nconst reactElement = htmlToReactParser.parse(htmlInput);\nconst reactHtml = ReactDOMServer.renderToStaticMarkup(reactElement);\n\nassert.equal(reactHtml, htmlInput); // true\n```\n\n### With Custom Processing Instructions\n\nIf certain DOM nodes require specific processing, for example if you want to capitalize each\n`\u003ch1\u003e` tag, the following example demonstrates this:\n\n```javascript\nconst ReactDOMServer = require('react-dom/server');\nconst HtmlToReact = require('html-to-react');\nconst HtmlToReactParser = require('html-to-react').Parser;\n\nconst htmlInput = '\u003cdiv\u003e\u003ch1\u003eTitle\u003c/h1\u003e\u003cp\u003eParagraph\u003c/p\u003e\u003ch1\u003eAnother title\u003c/h1\u003e\u003c/div\u003e';\nconst htmlExpected = '\u003cdiv\u003e\u003ch1\u003eTITLE\u003c/h1\u003e\u003cp\u003eParagraph\u003c/p\u003e\u003ch1\u003eANOTHER TITLE\u003c/h1\u003e\u003c/div\u003e';\n\nconst isValidNode = function () {\n  return true;\n};\n\n// Order matters. Instructions are processed in the order they're defined\nconst processNodeDefinitions = new HtmlToReact.ProcessNodeDefinitions();\nconst processingInstructions = [\n  {\n    // Custom \u003ch1\u003e processing\n    shouldProcessNode: function (node) {\n      return node.parent \u0026\u0026 node.parent.name \u0026\u0026 node.parent.name === 'h1';\n    },\n    processNode: function (node, children) {\n      return node.data.toUpperCase();\n    }\n  },\n  {\n    // Anything else\n    shouldProcessNode: function (node) {\n      return true;\n    },\n    processNode: processNodeDefinitions.processDefaultNode\n  }\n];\nconst htmlToReactParser = new HtmlToReactParser();\nconst reactComponent = htmlToReactParser.parseWithInstructions(htmlInput, isValidNode,\n  processingInstructions);\nconst reactHtml = ReactDOMServer.renderToStaticMarkup(reactComponent);\nassert.equal(reactHtml, htmlExpected);\n```\n\n### Replace the Children of an Element\n\nThere may be a situation where you want to replace the children of an element with a React\ncomponent. This is beneficial if you want to:\n- a) Preserve the containing element\n- b) Not rely on any child node to insert your React component\n\n#### Example\n\nBelow is a simple template that could get loaded via ajax into your application\n\n##### Before\n```html\n\u003cdiv class=\"row\"\u003e\n  \u003cdiv class=\"col-sm-6\"\u003e\n    \u003cdiv data-container=\"wysiwyg\"\u003e\n      \u003ch1\u003eSample Heading\u003c/h1\u003e\n      \u003cp\u003eSample Text\u003c/p\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\n##### After\n\nYou may want to extract the inner html from the `data-container` attribute, store it and then pass\nit as a prop to your injected `RichTextEditor`.\n\n```html\n\u003cdiv class=\"row\"\u003e\n  \u003cdiv class=\"col-sm-6\"\u003e\n    \u003cdiv data-container=\"wysiwyg\"\u003e\n      \u003cRichTextEditor html={\"\u003ch1\u003eSample heading\u003c/h1\u003e\u003cp\u003eSample Text\u003c/p\u003e\"} /\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\n#### Setup\n\nIn your instructions object, you must specify `replaceChildren: true`.\n\n```javascript\nconst React = require('react');\nconst HtmlToReact = require('html-to-react');\nconst HtmlToReactParser = require('html-to-react').Parser;\n\nconst htmlToReactParser = new HtmlToReactParser();\nconst htmlInput = '\u003cdiv\u003e\u003cdiv data-test=\"foo\"\u003e\u003cp\u003eText\u003c/p\u003e\u003cp\u003eText\u003c/p\u003e\u003c/div\u003e\u003c/div\u003e';\nconst htmlExpected = '\u003cdiv\u003e\u003cdiv data-test=\"foo\"\u003e\u003ch1\u003eHeading\u003c/h1\u003e\u003c/div\u003e\u003c/div\u003e';\n\nconst isValidNode = function () {\n  return true;\n};\n\nconst processNodeDefinitions = new HtmlToReact.ProcessNodeDefinitions();\n\n// Order matters. Instructions are processed in\n// the order they're defined\nconst processingInstructions = [\n  {\n    // This is REQUIRED, it tells the parser\n    // that we want to insert our React\n    // component as a child\n    replaceChildren: true,\n    shouldProcessNode: function (node) {\n      return node.attribs \u0026\u0026 node.attribs['data-test'] === 'foo';\n    },\n    processNode: function (node, children, index) {\n      return React.createElement('h1', {key: index,}, 'Heading');\n    }\n  },\n  {\n    // Anything else\n    shouldProcessNode: function (node) {\n      return true;\n    },\n    processNode: processNodeDefinitions.processDefaultNode,\n  },\n];\n\nconst reactComponent = htmlToReactParser.parseWithInstructions(\n  htmlInput, isValidNode, processingInstructions);\nconst reactHtml = ReactDOMServer.renderToStaticMarkup(\n  reactComponent);\nassert.equal(reactHtml, htmlExpected);\n```\n\n### With Preprocessing Instructions\n\nThere may be situations where you want to preprocess nodes before rendering them, analogously\nto the custom processing instructions functionality. The rationale for supporting preprocessing\nhooks is generally that you might want to apply more general processing to nodes, before\napplying custom processing hooks to filtered sets of nodes. You could accomplish the same by\ncalling common functions from your custom processing hooks, but the preprocessing hooks\nAPI makes it more convenient.\n\n#### Example\n\nBelow is a simple template in which you may want to replace div IDs, via a preprocessing hook:\n\n```html\n\u003cdiv class=\"row\"\u003e\n  \u003cdiv id=\"first\" data-process=\"shared\"\u003e\n    \u003cp\u003eSample For First\u003c/p\u003e\n  \u003c/div\u003e\n  \u003cdiv id=\"second\" data-process=\"shared\"\u003e\n    \u003cp\u003eSample For Second\u003c/p\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\nWe want to process the above HTML into the following:\n\n```html\n\u003cdiv class=\"row\"\u003e\n  \u003ch1 id=\"preprocessed-first\"\u003eFirst\u003c/h1\u003e\n  \u003ch2 id=\"preprocessed-second\"\u003eSecond\u003c/h2\u003e\n\u003c/div\u003e\n```\n\nWe can accomplish that with the following script, using a combination of preprocessing and\ncustom processing instructions:\n\n```javascript\nconst React = require('react');\nconst HtmlToReact = require('html-to-react');\nconst HtmlToReactParser = require('html-to-react').Parser;\n\nconst htmlToReactParser = new HtmlToReactParser();\nconst htmlInput = '\u003cdiv class=\"row\"\u003e' +\n  '\u003cdiv id=\"first\" data-process=\"shared\"\u003e' +\n    '\u003cp\u003eSample For First\u003c/p\u003e' +\n  '\u003c/div\u003e' +\n  '\u003cdiv id=\"second\" data-process=\"shared\"\u003e' +\n    '\u003cp\u003eSample For Second\u003c/p\u003e' +\n  '\u003c/div\u003e' +\n'\u003c/div\u003e';\n\nconst htmlExpected = '\u003cdiv class=\"row\"\u003e' +\n  '\u003ch1 id=\"preprocessed-first\"\u003eFirst\u003c/h1\u003e' +\n  '\u003ch2 id=\"preprocessed-second\"\u003eSecond\u003c/h2\u003e' +\n'\u003c/div\u003e';\n\nconst isValidNode = function () {\n  return true;\n};\n\nconst preprocessingInstructions = [\n  {\n    shouldPreprocessNode: function (node) {\n      return node.attribs \u0026\u0026 node.attribs['data-process'] === 'shared';\n    },\n    preprocessNode: function (node) {\n      node.attribs = {id: `preprocessed-${node.attribs.id}`,};\n    },\n  }\n];\nconst processNodeDefinitions = new HtmlToReact.ProcessNodeDefinitions();\nconst processingInstructions = [\n  {\n    shouldProcessNode: function (node) {\n      return node.attribs \u0026\u0026 node.attribs.id === 'preprocessed-first';\n    },\n    processNode: function(node, children, index) {\n      return React.createElement('h1', {key: index, id: node.attribs.id,}, 'First');\n    },\n  },\n  {\n    shouldProcessNode: function (node) {\n      return node.attribs \u0026\u0026 node.attribs.id === 'preprocessed-second';\n    },\n    processNode: function (node, children, index) {\n      return React.createElement('h2', {key: index, id: node.attribs.id,}, 'Second');\n    },\n  },\n  {\n    shouldProcessNode: function (node) {\n      return true;\n    },\n    processNode: processNodeDefinitions.processDefaultNode,\n  },\n];\n\nconst reactComponent = parser.parseWithInstructions(htmlInput, isValidNode, processingInstructions,\n  preprocessingInstructions);\nconst reactHtml = ReactDOMServer.renderToStaticMarkup(reactComponent);\nassert.equal(reactHtml, htmlExpected);\n```\n\n## Tests \u0026 Coverage\n\nTest locally: `$ npm test`\n\nTest with coverage and report coverage to Coveralls: `$ npm run test-coverage`\n\nTest with coverage and open HTML report: `$ npm run test-html-coverage`\n","funding_links":[],"categories":["HarmonyOS","Ramda"],"sub_categories":["Windows Manager","aknuds1/html-to-react"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faknuds1%2Fhtml-to-react","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faknuds1%2Fhtml-to-react","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faknuds1%2Fhtml-to-react/lists"}