javascriptreactjssvgvis.js

Render SVGSVGElement in React JS without dangerouslySetInnerHtml


Question: Can I render an SVGSVGElement in React without using dangerouslySetInnerHtml?

Context:

I am using the vis.js graph library, the getLegend method returns an SVGSVGElement object i.e. const icon = chart.getLegend(args); In the console I can see this:

in: icon instanceof SVGSVGElement
out: true
in: icon
out: <svg><rect x="0" y="0" width="30" height="30" class="vis-outline"></rect><path class="vis-graph-group0" d="M0,15 L30,15"></path></svg>

Problem:

When I try to render this in react using:

render (
<div> { icon } </div>
)

I get the following error:

Error: Objects are not valid as a React child (found: [object SVGSVGElement]). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of `LegendElement`

Workaround:

For now I am using: <svg dangerouslySetInnerHTML={{__html: icon.innerHTML}} />

But I was hoping for a straightforward solution that doesn't use a method with the word dangerous in the name.

Research:

I read this similar question but I don't think it helps for SVG generated at run time: How do I use an SVG in React without using dangerouslySetInnerHTML?


Solution

  • You can simple append the SVGSVGElement using a useRef like this. This example is for a functional component with hooks but can be adapted for class components.

    const svg = useRef(null);
    useEffect(()=>{
        if(svg.current){
            svg.current.appendChild(icon)
        } 
    }, []);
    
    return (
        <div ref={svg}/>
    );