Home > Net >  How do I <use> a named <tspan> element in an SVG document?
How do I <use> a named <tspan> element in an SVG document?

Time:12-10

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 above script any time you want.

  •  Tags:  
  • svg
  • Related