-
Notifications
You must be signed in to change notification settings - Fork 560
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: RawHTML Component #129
base: main
Are you sure you want to change the base?
Conversation
|
||
# Alternatives | ||
|
||
- https://github.com/remarkablemark/html-react-parser |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or safely render HTML (dangerously is bad). https://github.com/milesj/interweave
One day there was a proposal to use |
|
||
# Motivation | ||
|
||
Today in React, one must wrap dangerous html in an element ```<div dangerouslySetInnerHtml={{__html: `<span>ok</span>`}} />```. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to avoid adding new component, maybe would be better to extend Fragment
?
Example:
<Fragment dangerouslySetInnerHtml={{__html: '...'}} />
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See this comment on the issue linked directly above. It seems this RFC was created because the specific need of raw HTML is one created at the ReactDOM level, while Fragment comes from React proper.
I only need to point out while it is not relevant directly I have never seen an HTML Processing Framework that does not allow to easily use RAW HTML respect that point is earned by React. I will keep that example referenced for years it will illustrate how scary you can design a frontend lib. At present people need to parse HTML into a DOM Tree to parse it back into react create an element and react itself offers nothing to assist in that process. compare that to for example vue it uses raw html :) nothing needed to use rawHtml :) |
I really dont understand why this is not possible right now... |
I think, since React gets used more and more with things like gatsby and thus with CMS's, a RawHTML-Component would make sense. |
Is there a workaround that is available now? EDIT: Look like the most solid workaround is Interweave - it supports SSR as well! |
@tyteen4a03 yes that is one possible solution the general solution is to use a parser like "parse5": "^5.1.1", thats what your package is using and write a tree adapter for react i am working on one at present |
I feel like this would be a very helpful feature for the project I'm currently working on. 👍 Doing universal rendering with micro frontends created a demand for being able to inject raw HTML inside React components for us and I don't feel like serving the entire HTML parser to the client just to get rid of the redundant wrapper. Is there a consensus on I hope this gets RFC some attention! |
This feature will make injecting custom html into _document in next.js much easier. vercel/next.js#3105 vercel/next.js#3904 |
Hey @bvaughn 👋 you mentioned the best way forward is the RFC process. Can you help direct us what the next step is from here? I saw the README mentioned "Eventually, the team will decide whether the RFC is a candidate for inclusion" but it's unclear if we need to ping you all, or maybe submit this RFC for team review perhaps? |
@jayphelps RFC process is still the appropriate path for this kind of issue/feature, but we can't guarantee any kind of timeline for RFC review or approval. (For what it's worth, the team does generally try to read and keep up-to-date with open RFCs. The approval process can be very time consuming on our side though and we just don't have the bandwidth for much extra at the moment.) |
My use case for this is in a gatsby project using server side rendering (gatsby-ssr.js) to populate the contents of head with the inline script for a NewRelic Browser Agent fetched using this api which produces a json document with the NewRelic loader script e.g.:
So wrapping the contents of loader_script in a div would of-course be incorrect. There are other ways I can solve this, however the proposed RawHTML would be the cleanest! |
``` | ||
|
||
```html | ||
<html><head><script src="/app.js"></script> <link href="/styles.css" /></head><body>hello</body></html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this RFC, but I'm not sure if this case is clear enough 🤔 Just to make sure, do we really need this feature? No workaround here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have the same problem and I just want to inject a JS snippet.
In the spirit of #182 — no particular update on this. We're doing work on a new streaming server renderer (reactwg/react-18#37) so I'll check with the team if there are any new constraints that would influence this. |
A use case of this is to render something like this: ['<p>', someReactElement, '</p>'] with react fragments accepting [
<React.Fragment dangerouslySetInnerHTML={{__html: '<p>'}} />,
someReactElement,
<React.Fragment dangerouslySetInnerHTML={{__html: '</p>'}} />
] As far as I understand if this array is generated dynamically, this is something not possible to achieve with React and there is no workaround. Edit: Does anyone know if it is possible at all to support this with current features of the DOM? |
@sassanh it is possible the current state is you take a HTML/Parser and then you write a small script that translates the resulting PARSER-DOM to React-DOM in this issue are some links to existing solutions you should read it complet |
@frank-dspeed Thanks! But I took a quick look but I really doubt if |
@sassanh as interwave is a react-element you can put your other react element next to it <inter.... /><your-component ..... /><inter ...... />
[
<inter ..../>,
someReactElement,
<inter ... />
] with the matchers you could code a custom matcher that injects your react element into a single <inter ... /> |
I think interweave is not solving the problem I mentioned, if I wanted to parse the text containing the HTML elements and get aware of its structure I could resolve the issue without interweave too, but if React supported something like this:
which I think is extremely hard to support, then I didn't need to be aware of the structure of the string passing to [
<ReactDOM.RawHTML dangerouslySetInnerHTML={{__html: veryComplexHTMLPart1}} />,
aReactElementBasedOn_veryComplexHTMLPart2_,
<ReactDOM.RawHTML dangerouslySetInnerHTML={{__html: veryComplexHTMLPart3}} />
] |
A usecase that would be a bit easier to achieve: <>
{/* It is not possible to render the html of a React-rendered component without a container
because dangerouslySetInnerHTML is the only route to get raw html into the resulting html */}
<kaliber-component-container dangerouslySetInnerHTML={{ __html: renderedComponent }} />
{/* Use render blocking script to remove the container and supply the correct comment nodes.
This ensures the page is never rendered with the intermediate structure */}
<script dangerouslySetInnerHTML={{ __html: restructureDomNodes(componentInfo) }} />
</> function restructureDomNodes(componentInfo) {
return `|var d=document,s=d.currentScript,p=s.parentNode,c=s.previousSibling;
|p.setAttribute('${containerMarker}',''); // set marker on container so we can retrieve nodes that contain components
|p.replaceChild(d.createComment('start'),c); // replace kaliber-component-container element with a 'start' comment
|p.insertBefore(d.createComment(JSON.stringify(${componentInfo})),s); // create a comment containing the component info
|Array.from(c.childNodes).forEach(x=>{p.insertBefore(x,s)}); // insert all children from the kaliber-component-container element
|p.replaceChild(d.createComment('end'),s); // create an 'end' comment
|`.replace(/^\s*\|/gm, '').replace(/\s*\/\/.*$/gm, '').replace(/\n/g, '')
} We use this to render components without a container on the server. On the client we extract the nodes to This strategy allows us to render layout containers on the server and have CSS layout their interactive children without the hassle of an 'unneeded' container around the interactive child. |
React is a cross-platform framework (React Native, Ink, other custom renderers etc.), so DOM-specific props on |
@satya164 Right, I will replace |
This probably isn't a huge interest, but I'm working on writing a tool to translate google closure templates (aka soy templates) into React/JSX and this would be really helpful in maintaining the output behavior |
I know this is a hack but for my use case this allows me to inject arbitrary html inside const RawHtml = ({ html = "" }) => (
<script dangerouslySetInnerHTML={{ __html: `</script>${html}<script>` }} />
); Usage: const EmailHead = ({ title = "" }) => {
return (
<head>
<title>{title}</title>
<RawHtml html={`<!--[if !mso]><!--><meta http-equiv="X-UA-Compatible" content="IE=edge"><!--<![endif]-->`} />
</head>
)
} The output will leave some empty <html>
<head>
<title>Title</title>
<script></script>
<!--[if !mso]><!-->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!--<![endif]-->
<script></script>
</head>
<body></body>
</html> EDIT: Simplified usage a little bit, also if you're planning to use ReactDOMServer.renderToStaticMarkup(<MyRootComponent />)
// Remove `<RawHtml />` injected scripts
.replace(/<script><\/script>/g, "") |
I found many opensource participants, but no one from React team with power to check if this RPC is acceptable or need to be upgrade? I know there is no guarantee for RFC timeline, but it has been 2 years. |
@denghongcai the problem is that it does not rely work with the core principles of how react works react parses dom and or html strings into unfed react dom model so the way to create compat is to parse html to the react dom model to enable raw HTML while out of dev view it is more simple to isolate react components into its own parts and not attach a parsed tree to the react part maybe i should draw a model to make that more understand able. <raw html />
<some_react /> never! <raw html />
<some_react><raw html /></some_react> i know this maybe gets downvotes because it is handy to take react apps that use the whole document and then modifie them but thats how react is that is not my opinion but the code that is needed to take raw html to react dom is a beast it self. all existing solutions do parse the HTML to ReactDOM |
Obviously this is incredibly stalled, but is there any possibility of |
I would love to have this feature. I currently have a need to insert regular HTML comment in the React rendered application, that will be not removed during the rendering, and there is not easy way to do it. I can do workaround with |
No description provided.