Convert HTML to React components using recursion
Do you need to transform an HTML string into React components, but don't want to do it manually?
There are several handy libraries that can automate this for you:
But maybe you have a more custom use case, or you're just curious how it's done.
Here's how you can do it yourself with a simple recursive function.
Setup
We'll use a couple of dependencies to make things easier:
- himalaya to parse the HTML and serialize it to JSON
- html-attribute-to-react to convert the HTML attributes to React props
yarn add himalaya html-attribute-to-react --save
Code
// convertToComponents.js
import React from 'react';
import { parse } from 'himalaya';
import htmlAttributeToReact from 'html-attribute-to-react';
function buildComponentTree(nodes) {
return nodes.map((node, i) => {
switch (node.type) {
case 'text':
// Node is just a string, so return it as is
return node.content;
case 'element':
// Recursively get nodes for element's children
const children = buildComponentTree(node.children);
// Convert element's attributes to React props
const attrs = node.attributes.reduce(
(acc, attr) => ({
...acc,
[htmlAttributeToReact(attr.key)]: attr.value,
}),
{}
);
// Create React element
return React.createElement(
node.tagName,
{ ...attrs, key: `${node.type}-${i}` },
children.length ? children : null
);
default:
// Return null for any non-text/element nodes
return null;
}
});
}
export default function convertToComponents(html) {
return buildComponentTree(parse(html));
}
Then you can import this module into your component files, and use it like this:
// SomeComponent.js
import React from 'react';
import convertToComponents from './convertToComponents';
const SomeComponent = () => {
return (
<div>
{convertToComponents(
'<p>I will be transformed into React!</p>'
)}
</div>
)
}
export default SomeComponent;