Reputation: 26054
I am trying to use svg
with <defs>
defined elsewhere in the page.
const data = {
icons: {
freezable: "<svg><path d=""/></svg>",
vegetarian: "<svg><path d=""/></svg>",
}
};
const SvgDefs = (icons) => {
return Object.keys(icons).map(iconName => {
return <span key={data.icons[iconName]} dangerouslySetInnerHTML={{
__html: data.icons[iconName].replace('svg', `svg id="svg-${iconName}"`)
}} />;
});
};
With my component rendering this as:
return <svg aria-hidden="true" id="svgdefs" xmlns="http://www.w3.org/2000/svg">
<defs>
<SvgDefs icons={data.icons} />
</defs>
</svg>
However, when I check the Elements tab in Chrome Dev Tools, I see that the spans containing the svgs are outside of the <defs>
block:
What am I doing wrong here?
Upvotes: 0
Views: 977
Reputation: 53598
The problem comes from you calling your functional component's input argument icons
, and the assumptions that stem from that naming choice.
Functional components are passed JSX properties wrapped up in an object, conventionally called props
, so call your function input props
and then get your data back out from that. Since you passed icons=...
, you'll need access that data through props.icons
:
const SvgDefs = (props) => {
const { icons } = props;
return Object.entries(icons).map(([name, html]) => {
return <span key={name} dangerouslySetInnerHTML={{
__html: html.replace('svg', `svg id="svg-${name}"`)
}} />;
});
};
Although it would make a lot more sense to not have SVG strings in your data.icons to begin with: just have more JSX so you don't need to dangerously set innerHTML at all.
Upvotes: 1
Reputation: 26054
I discovered that the reason was because <span>
cannot be used inside <defs>
. I used <symbol>
instead and all worked as expected.
Upvotes: 0