milesj / interweave

🌀 React library to safely render HTML, filter attributes, autowrap text with matchers, render emoji characters, and much more.
https://interweave.dev
MIT License
1.09k stars 38 forks source link

SVG tags are not rendering #225

Open rahujoshi opened 2 years ago

rahujoshi commented 2 years ago

https://codesandbox.io/s/target-first-child-css-styled-components-forked-7p64n0?file=/src/index.js

I am getting SVG string from the backend I want to render it in my React app...But I am not able to achieve it.. see the code link at the top

milesj commented 2 years ago

@rahujoshi Interweave was only designed for HTML as it parses it with the DOM, SVG wont work.

I'm not sure why you would run SVGs through interweave anyways.

dantabel commented 2 years ago

@rahujoshi I have this issue too. SVG attributes use camel case like viewBox but Interweave converts all attributes to lowercase. I have inline SVGs as part of a HTML string hence needing to use Interweave. My only solution was to use dangerouslySetInnerHTML instead.

@milesj inline SVGs are valid in HTML (e.g. https://www.w3schools.com/html/html5_svg.asp) so the DOM should be able to parse it fine. If you have SVGs as part of a HTML string you would expect them to be rendered I would have thought. With allowElements and allowAttributes set to true, it's just the camelCase attributes being lowercased that stop it from rendering properly.

milesj commented 2 years ago

It depends on whether createHTMLDocument supports parsing SVG correctly or not, which is what Interweave uses under the hood.

I can't recall off the top of my head.

dantabel commented 2 years ago

Thanks for your response. I've just had a play around in code sandbox. You need to use createElementNS to create an element in the SVG namespace, using createElement didn't work. So doc.createElementNS("http://www.w3.org/2000/svg", "svg") works.

I understand that this probably makes this too much of a hassle for you as you'd have to identify all of the SVG elements and process them differently.

dantabel commented 2 years ago

To solve my issue I've written the following transform function. I know it's not particularly safe, but I trust the source HTML, so it works for me.

const transform = (node: HTMLElement, children: Node[]): React.ReactNode => {
    const namespaces = [
        'http://www.w3.org/1998/Math/MathML',
        'http://www.w3.org/2000/svg'
    ]
    if(node.namespaceURI && namespaces.includes(node.namespaceURI)){
        const attributes:{[att:string]: string|null} = {}
        node.getAttributeNames().forEach(attName => {
            attributes[attName] = node.getAttribute(attName)
        })
        return React.createElement(node.tagName, attributes, children) 
    }
    return undefined
}
milesj commented 2 years ago

Awesome transformer. This may be a quick win to support it in core in the future.

overtureweb commented 12 months ago

@rahujoshi Interweave was only designed for HTML as it parses it with the DOM, SVG wont work.

I'm not sure why you would run SVGs through interweave anyways.

I'm using Interweave to parse an HTML doc received in an AJAX response to an API call. Some of the HTML docs contain SVG elements. I don't think it's unreasonable to assume that could be the case. IW is an awesome utility and would love to see support for SVG elements added. FTM I'm using @dantabel's excellent suggestion.