Skip to content
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

@html directive doesn't work as direct child of svg #5764

Open
csenio opened this issue Dec 9, 2020 · 9 comments
Open

@html directive doesn't work as direct child of svg #5764

csenio opened this issue Dec 9, 2020 · 9 comments

Comments

@csenio
Copy link

csenio commented Dec 9, 2020

Describe the bug

If I have a component like this

  // dynamic.svelte
  {@html `<circle cx="500" cy="500" r="200"></circle>`}	

and try to render it like this

   <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080">
     <Dynamic />
  </svg>

The circle isn't rendered.

To Reproduce
https://svelte.dev/repl/1a2ea34b898040e7bd52928331f6437b?version=3.31.0

Expected behavior
The circle should be rendered

Severity
Minor annoyance, there are 2 workarounds (see Additional context)

Additional context

If I wrap the html directive in a <g> tag like this:

<g>
  {@html `<circle cx="500" cy="500" r="200"></circle>`}	
</g>  

or use it without a component

   <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080">
     {@html `<circle cx="500" cy="500" r="200"></circle>`}	
  </svg>

it works fine

@peopledrivemecrazy
Copy link
Contributor

Very interesting!

@chimp1nski
Copy link

chimp1nski commented Dec 14, 2020

I'd say that SVG XML !== HTML maybe?
@html probably doesn't know how to parse the <circle/> tag since it's not a valid HTML tag.

Edit: Hmm .. your working examples actually debunk that theory - feel free to ignore the comment above!

@dimfeld
Copy link
Contributor

dimfeld commented Jan 1, 2021

The difference here is that the standalone component uses an HtmlTag class to add the <circle> HTML, while the others just set innerHTML on the container. The latter appears to be an optimization when there is only an @html and nothing else inside an element.

So that means that this also reproduces the bug, since it uses an HtmlTag to add the @html contents:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080">
  <circle cx="200" cy="500" r="200"></circle>
  {@html `<circle cx="500" cy="500" r="200"></circle>`}
</svg>

In the above case the circle at cx=200 appears while the circle at cx=500 does not. Oddly, the browser devtools actually do show the <circle ...> markup as expected. But when examining the elements, I see this on the working one:
image

Meanwhile, that section is missing completely on the broken element, as if the attributes are not actually being set somehow. Likewise, examining an attribute on the two elements returns undefined in the broken case but an attribute, as expected, in the working case:

image

My best guess is that HtmlTag is using document.createElement to create the element that stores the rendered text, but it may need to use document.createElementNS with the appropriate namespace when inside an SVG. Not 100% sure on that though.

I'm also not sure how easy this will be to detect since it seems like it would require walking all the way up the component tree at runtime to see if the element is inside an SVG, and also accounting for foreignObject and so on. Not great, but maybe someone knows a better way?

Workaround

All this means that the proper workaround is to always wrap an @html directive inside an SVG with a <g> (or any other SVG element) and put nothing else inside that <g>.

@timvanoostrom
Copy link

timvanoostrom commented Mar 25, 2021

A side-effect of the bug is that svg case-sensitive attributes are all lowercased when inserted into the DOM.

Results in incorrect behavior
{@html '<pattern patternUnits="userSpaceOnUse">...</pattern>'} => patternunits="userSpaceOnUse"

Results in desired behavior
<g>{@html '<pattern patternUnits="userSpaceOnUse">...</pattern>'}</g> => patternUnits="userSpaceOnUse"

@stale
Copy link

stale bot commented Jun 26, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale-bot label Jun 26, 2021
@stale stale bot removed the stale-bot label Jun 26, 2021
@stale stale bot removed the stale-bot label Jun 27, 2021
@stale
Copy link

stale bot commented Dec 24, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale-bot label Dec 24, 2021
@louisabraham
Copy link

Hi, just stumbled on this issue (actually on the repl page). Thank you a lot for the <g> workaround. I think this is a real issue and should not be marked stale.

@brunnerh
Copy link
Member

I would suggest extending @html with a second, optional argument that can be used to specify the current namespace, if Svelte is unable to determine it correctly.

@gka
Copy link
Contributor

gka commented Mar 6, 2024

Also stumbled on this bug today, it still exists in Svelte 4 and Svelte 5. The workaround with the extra <g> is not feasable as it comes with a significant performance overhead. Would be nice if this would be fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants