Is it possible to insert HTML string into Head?
Answered
White-chinned Petrel posted this in #help-forum
White-chinned PetrelOP
I get HTML rendered as a string from a trusted server that includes link and script tags which I want to insert in Head (and in body too, which is probably the same problem).
I have tried to wrap it in script and div using dangerouslySetInnerHtml already and don't have any other ideas.
My best shot now is probably to use some third-party package that can parse HTML into React elements, which is not ideal.
Any help is appreciated 🙏
I have tried to wrap it in script and div using dangerouslySetInnerHtml already and don't have any other ideas.
My best shot now is probably to use some third-party package that can parse HTML into React elements, which is not ideal.
Any help is appreciated 🙏
Answered by joulev
I have this same problem at work too. After many many attempts, we found that this is the only way to make it work:
All other methods we could think of, such as
don’t work, one way or another.
"use client";
import parse, { Element, Text } from "html-react-parser";
import { useEffect, useState } from "react";
export function CustomHtml({ customHtml }: { customHtml: string }) {
const [isMounted, setIsMounted] = useState(false);
useEffect(() => setIsMounted(true), []);
if (!isMounted) return null;
return parse(customHtml, {
// https://github.com/remarkablemark/html-react-parser/issues/98
replace: domNode => {
if (!(domNode instanceof Element)) return;
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison -- How to fix it then?
if (domNode.type === "script") {
const script = document.createElement("script");
for (const key in domNode.attribs) script.setAttribute(key, domNode.attribs[key]);
if (domNode.children.length !== 0 && domNode.children[0] instanceof Text)
script.innerHTML = domNode.children[0].data;
document.head.appendChild(script);
}
},
});
}All other methods we could think of, such as
;<script
dangerouslySetInnerHtml={{
__html: `</script>${html}<script>`,
}}
/>don’t work, one way or another.
2 Replies
@White-chinned Petrel I get HTML rendered as a string from a trusted server that includes link and script tags which I want to insert in Head (and in body too, which is probably the same problem).
I have tried to wrap it in script and div using dangerouslySetInnerHtml already and don't have any other ideas.
My best shot now is probably to use some third-party package that can parse HTML into React elements, which is not ideal.
Any help is appreciated 🙏
I have this same problem at work too. After many many attempts, we found that this is the only way to make it work:
All other methods we could think of, such as
don’t work, one way or another.
"use client";
import parse, { Element, Text } from "html-react-parser";
import { useEffect, useState } from "react";
export function CustomHtml({ customHtml }: { customHtml: string }) {
const [isMounted, setIsMounted] = useState(false);
useEffect(() => setIsMounted(true), []);
if (!isMounted) return null;
return parse(customHtml, {
// https://github.com/remarkablemark/html-react-parser/issues/98
replace: domNode => {
if (!(domNode instanceof Element)) return;
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison -- How to fix it then?
if (domNode.type === "script") {
const script = document.createElement("script");
for (const key in domNode.attribs) script.setAttribute(key, domNode.attribs[key]);
if (domNode.children.length !== 0 && domNode.children[0] instanceof Text)
script.innerHTML = domNode.children[0].data;
document.head.appendChild(script);
}
},
});
}All other methods we could think of, such as
;<script
dangerouslySetInnerHtml={{
__html: `</script>${html}<script>`,
}}
/>don’t work, one way or another.
Answer
@joulev I have this same problem at work too. After many many attempts, we found that this is the only way to make it work:
tsx
"use client";
import parse, { Element, Text } from "html-react-parser";
import { useEffect, useState } from "react";
export function CustomHtml({ customHtml }: { customHtml: string }) {
const [isMounted, setIsMounted] = useState(false);
useEffect(() => setIsMounted(true), []);
if (!isMounted) return null;
return parse(customHtml, {
// https://github.com/remarkablemark/html-react-parser/issues/98
replace: domNode => {
if (!(domNode instanceof Element)) return;
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison -- How to fix it then?
if (domNode.type === "script") {
const script = document.createElement("script");
for (const key in domNode.attribs) script.setAttribute(key, domNode.attribs[key]);
if (domNode.children.length !== 0 && domNode.children[0] instanceof Text)
script.innerHTML = domNode.children[0].data;
document.head.appendChild(script);
}
},
});
}
All other methods we could think of, such as
tsx
;<script
dangerouslySetInnerHtml={{
__html: `</script>${html}<script>`,
}}
/>
don’t work, one way or another.
White-chinned PetrelOP
Yep, it does work actually, thanks a lot!
Now the problem is that either React or Next.js seem to simply cut off some of the scripts from DOM for no reason.
Now the problem is that either React or Next.js seem to simply cut off some of the scripts from DOM for no reason.
