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

SVG elements not displaying when passed as slot content #7807

Open
mhkeller opened this issue Aug 25, 2022 · 5 comments
Open

SVG elements not displaying when passed as slot content #7807

mhkeller opened this issue Aug 25, 2022 · 5 comments

Comments

@mhkeller
Copy link

Describe the bug

If you have an SVG component that allows you to pass in child content as a slot like so...

<svg width="150" height="50">
  <slot></slot>
</svg>

...no content will display if you pass in content wrapped in an anchor tag like so...

<script>
  import Svg from './Svg.svelte';
</script>

<Svg>
  <a href="https://example.com">
    <path d="M0,0L50,50Z" stroke="#000" stroke-width="2"></path>
  </a>
</Svg>

However, if you don't use an SVG component and simply write plain SVG, everything displays fine.

<svg width="150" height="50">
  <a href="https://example.com">
    <path d="M0,0L50,50Z" stroke="#000" stroke-width="2"></path>
  </a>
</svg>

It seems that something is breaking when the child content gets sent through the slot.

Reproduction

https://svelte.dev/repl/08270639a2154ea18192cbdf30861da8?version=3.49.0

Logs

No response

System Info

REPL

Severity

blocking all usage of svelte

@Prinzhorn
Copy link
Contributor

Prinzhorn commented Aug 25, 2022

Very similar to #7450 and #7563 (basically a duplicate I would say)

Array.from(document.querySelectorAll('a')).map(e => e.namespaceURI)

0: "http://www.w3.org/2000/svg" <=============
1: "http://www.w3.org/1999/xhtml" 

@peufo
Copy link

peufo commented Dec 22, 2022

If you can't add <svelte:options namespace="svg"> into all nested components you can use this action :

<script lang="ts">

  /** Ensure all "a" elements inside an SVG node belong to the correct namespace */
  function ensureSVGA(node: SVGSVGElement) {
    const namespaceSVG = 'http://www.w3.org/2000/svg'
    const links = node.querySelectorAll<HTMLLinkElement>('a')
    for (const link of links) {
      if (link.namespaceURI === namespaceSVG) continue
      const a = document.createElementNS(namespaceSVG, 'a')
      for (const { name, value } of link.attributes) {
        a.setAttribute(name, value)
      }
      a.append(...link.children)
      link.insertAdjacentElement('beforebegin', a)
      link.remove()
    }
  }
</script>

<svg use:ensureSVGA>
  <slot />
</svg>

@mhkeller
Copy link
Author

I've found a similar problem when loading SVG defs via a svelte:fragment when the svg element is also a slot and the parent element is an HTML div.

Here's the repro: https://svelte.dev/repl/2647caa253d648428dfd96b8d1d6b974?version=3.55.0

If you comment out the main wrapper div, svelte is able to detect the SVG namspace and the gradient shows up. If you wrap the whole thing in a div, it will interpret <linearGradient> an HTML tag. I tried adding <svelte:options namespace="svg"/> to the Svg.svelte component but that has no effect.

@peufo
Copy link

peufo commented Dec 25, 2022

@mhkeller can you <svelte:options namespace="svg"/> in nested component? https://svelte.dev/repl/822371299ddf401885091c66715c66f7?version=3.55.0

@mhkeller
Copy link
Author

Yes that it as a viable workaround for now – similar to adding the xmlns attribute inline to the linearGradient tag. It would still be nice if Svelte detected that the children of the defs object were svg elements, though.

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

No branches or pull requests

3 participants