#15639·Vue.js

Async component resolved under <Suspense> is mounted with the Suspense's namespace, so SVG children become HTML elements

Author: alessaloisioCreated Sep 24, 2026Updated Sep 29, 2026
Labels:hammer: p3-minor-bug

Vue version

3.5.43 (also reproduces on the SFC Playground's latest main build)

Link to minimal reproduction

https://play.vuejs.org/#eNq1k1GP0kAQx7/KpJprG3tb4NREKE2ITyZ3iTn0yZpcbQe62u6uu1s4QvrdnW3LyQNqTPQF2JnMf/6/meHorZRiuxa9OXiJKTRXFgzaVqWZ4I2S2sIRStxwgStzEMVbSUGBwkZQRSDFnWyFxTICjRvoYKNlAz7p+ZnIRBzDPYoStYEcDBfbGiFRua3SBXBrQOQNGpUXCNxQk4KXWMK+QkFZF2oGcZaJQgpj4ZZcwJIM6V51DkEIyxSqwHeifuSszsG/m06iVxO4nb5x3xQ2VstvSBnia4wUFPKH2PWel1Q5h9fQhdCdGvWoY7dL8MHQ+D3RcoNMo5H1DgNXEYaOfJDR2A9w6YYT+D5lngY2KtCoP/AGZXuSPGYCxjq2y+vWOfjEGCtl0TbUmX1vUR/WWGNhpV7V9cgefnaFAKzJVRC4UC/38PzofrMytzn1YgV9dnMYo0/z/3j/rnsIR4WvkovAzzLhDHcRzCYTB5XEw3mkji+x2Kg6t5i6okSlUwZrmhAUpxEBF3BV24XZba+2dhFB61bWh9atUSgMungSq0HiFEwHFwnVQb+cZeaRg8yDCvm2svSc9k9jDzXS64vU/S1M1SPQGngJz4qiyLw06RfoyK8dtitk4NYIL+DUjXTilMh228FFfGZjJJux4Rx+gybkr7n+AcfPazyHIV+5S/TtL/KMADd/Bri8G8ja2WT60unXfXed78X/XNhl0JsR9K/WpjE9Hk9/wK4j19olk/jscL3uB66dpwA=

Steps to reproduce

Open the reproduction. It renders the same component — whose root is a single <path> — inside an <svg> three times:

  1. a sync component, under <Suspense>;
  2. an async component (defineAsyncComponent), without <Suspense>;
  3. the same async component, under <Suspense>.

The <pre> at the bottom prints each <path>'s namespaceURI.

What is expected?

The line is drawn in all three <svg>s, and every <path> has the SVG namespace (http://www.w3.org/2000/svg).

What is actually happening?

Case 3 draws nothing: its <path> is created as an HTML element (http://www.w3.org/1999/xhtml) inside the <svg>.

1. sync + Suspense: http://www.w3.org/2000/svg
2. async, no Suspense: http://www.w3.org/2000/svg
3. async + Suspense: http://www.w3.org/1999/xhtml

With suspensible: false on the async component, the path is an SVG element again.

System Info

bash
System: macOS 26.6.2 (Darwin 25.6)
Browsers: Chrome
npmPackages: vue 3.5.43

Any additional comments?

Under a <Suspense>, a suspensible async component's setup is registered as a dependency of the boundary (suspense.registerDep). When it resolves, registerDep calls setupRenderEffect(instance, vnode, parentNode(...), anchor, suspense, namespace, optimized) where namespace is the one createSuspenseBoundary received — the namespace of the <Suspense> itself, not the one of the position the component was rendered at (svg here). The component's subtree is then mounted with the boundary's namespace.

We hit it with graph libraries (Vue Flow custom edge types) in an app that registers its components with defineAsyncComponent and renders pages under a <Suspense>: the edges' <path>s were in the DOM, with valid coordinates, but not drawn. Reproduced outside the browser as well (jsdom + createApp, Vue 3.5.43), with the same result.