Last active
October 23, 2020 21:35
-
-
Save TylerBarnes/1498165c5f7ec60354bce6a576ea5934 to your computer and use it in GitHub Desktop.
How to map html DOM elements to React components by tag name.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react" | |
import { HtmlToReact } from "./parse-html-to-react.js" | |
import { Link, Box } from "some-ui-package" | |
function MyPage(props) { | |
const { html } = props | |
return ( | |
<div> | |
<h1>My page!</h1> | |
{ | |
HtmlToReact( | |
html, | |
{ | |
// element attributes and children will be automatically passed to mapped | |
// react components | |
a: Link, // this replaces any anchor tags <a> with the Link component <Link> | |
div: Box // any divs will be replaced with <Box> | |
} | |
) | |
} | |
</div> | |
) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ReactHtmlParser from "react-html-parser" | |
export const HtmlToReact = (html, components) => { | |
if (!html) { | |
return null | |
} | |
const transform = (node) => { | |
if (node.type !== "tag") { | |
return | |
} | |
const componentName = node.name.charAt(0).toUpperCase() + node.name.slice(1) | |
const Component = components[componentName] | |
const props = { | |
...node.attribs, | |
style: getStyleObjectFromString(node.attribs.style), | |
} | |
if (props.class) { | |
props.className = props.class | |
delete props.class | |
} | |
if (Component && node?.children?.length) { | |
return ( | |
<Component {...props}> | |
{node.children.map((child) => { | |
if (child.type === `text`) { | |
return child.data | |
} | |
return transform(child) | |
})} | |
</Component> | |
) | |
} else if (Component) { | |
return <Component {...props} /> | |
} | |
return null | |
} | |
const Component = ReactHtmlParser(html, { | |
transform, | |
}) | |
return Component | |
} | |
export const getStyleObjectFromString = (styles) => { | |
if (!styles) { | |
return | |
} | |
const style = {} | |
styles.split(";").forEach((declaration) => { | |
const [property, value] = declaration.split(":") | |
if (!property) return | |
const formattedProperty = formatStringToCamelCase(property.trim()) | |
style[formattedProperty] = value.trim() | |
}) | |
return style | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment