Home > front end >  Can I render static html content in React without injecting styles?
Can I render static html content in React without injecting styles?

Time:04-04

I'm currently builidng a service that lets users create email templates. Users can preview the templates in the UI. The html for the preview is rendered on the server and send to the client. I currently render the "escaped" and "sanitized" content like this:

<div dangerouslySetInnerHTML={{ __html: digestPreview }} />

The problem with this approach is that the templates contain style tags like: <style>h1 {color: red}</style>.

This style will be injected into the rest of the page and messes up the rendering of all h1 tags on the screen. Not just the ones within the div that has the innerHTML prop set.

I'm looking for a way to render the html without injecting the styles. I don't want to convert all my styles to inline css.

CodePudding user response:

You can try using <iframe>.

An example:

import { useEffect, useRef } from "react";
import "./styles.css";

export default function App() {
  const iframeRef = useRef();

  useEffect(() => {
    const iframeDoc = iframeRef.current.contentWindow.document;
    iframeDoc.open("text/html", "replace");
    iframeDoc.write(
      "<style>h1 { color: red }</style><h1>Header inside iframe</h1>"
    );
    iframeDoc.close();
  }, []);

  return (
    <div className="App">
      <h1>Styled H1 in the app</h1>
      <iframe ref={iframeRef} src="about:blank" title="myIframe" />
    </div>
  );
}

Full available here: https://codesandbox.io/s/vibrant-drake-000u0x?file=/src/App.js.

Another way is to use Shadow DOM.

CodePudding user response:

Perhaps you can apply a filter on the digestPreview to remove the styles before passing the markup down.

const htmlString = `
<body>
<style>
h1 {color: red;}
</style>
<h1>hello</h1>
<p>
<style>
h1 {color: red;}
</style>
world
</p>
</body>
`;

function toStylelessDocument(htmlString) {
  const doc = (new DOMParser()).parseFromString(htmlString, "text/html");

  var treeWalker = document.createTreeWalker(
    doc,
    NodeFilter.SHOW_ELEMENT, {
      acceptNode: function(node) {
        if (node.tagName === 'STYLE') {
          return NodeFilter.FILTER_ACCEPT;
        }
      }
    },
    false
  );


  let currentNode = treeWalker.currentNode;
  const styles = [];
  while (currentNode) {
    if (currentNode.tagName === "STYLE") {
      styles.push(currentNode)
    }
    currentNode = treeWalker.nextNode();
  }
  for (let style of styles) {
    style.parentElement.removeChild(style);
  }
  return doc;
}

d = toStylelessDocument(htmlString);
console.log(d.body.innerHTML);

You can use the toStylelessDocument function create an HTMLDocument with the style elements removed from the DOMtree.

const stylelessDocument = toStylelessDocument(digestPreview);

<div dangerouslySetInnerHTML={{ __html: stylelessDocument.body.innerHTML }} />
  • Related