I'm trying to define a tspan
early in an SVG document so it can be transcluded later inside a text
. At least in Firefox, the following code does not produce this result.
<svg version="1.1" width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<tspan id="transcluded-text">This is a text</tspan>
</defs>
<text>
<use href="#transcluded-text"/>
</text>
</svg>
Using Firefox's Inspect tool, the use
element contains a shadow DOM (#shadow-root
) as expected, but the shadow DOM itself is empty.
Without using Javascript, is it possible to transclude a tspan
inside a text
like this?
CodePudding user response:
The text element can only contain text content child elements (so, not <use>
) and the only text related element the defs element can contain is <text>
. So, it all points to that the <tspan>
cannot be used in this way.
<svg version="1.1" width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<text x="10" y="20" font-size="20" id="transcluded-text">This is a text</text>
</defs>
<use href="#transcluded-text"/>
</svg>
CodePudding user response:
Since you can not use <use>
elements within a <text>
element;
or a bare <tspan>
within <defs>
A modern Native Web Component can do the replace job:
(this will cause a FOUC you might want to deal with)
<script>
customElements.define("svg-use-replacer", class extends HTMLElement {
connectedCallback() {
setTimeout(() => { // make sure SVG is parsed
this.querySelectorAll('use').forEach(use => {
let href = use.getAttribute("href");
let tspan = this.querySelector(href);
use.replaceWith(tspan); // .replaceWith was not available in IE
});
// if the bare <svg> is required in the DOM:
// this.replaceWith(this.querySelector("svg"));
});
}
});
</script>
<svg-use-replacer>
<svg version="1.1" width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<tspan id="foo" stroke="green">Wonderful</tspan>
</defs>
<text x="10" y="20" font-size="20">
Hello
<use href="#foo" /> Web Component
</text>
</svg>
</svg-use-replacer>
Notes
The oldskool way is to attach a class and after that Element is parsed run JavaScript on it.
With Web Components it totally does not matter WHEN the Web Component is defined.
You can execute the abovescript
any time you want.