<use> SVG in Javascript
To use fragmentioner and marginalia on my site, I want to insert SVG icons into the HTML pages. Sounds simple unless you check all the browsers — Chrome and Opera just behave weirdly!
Below is a sample of the SVG markup we would like to insert. It uses the <use>
-tag to refer to an external SVG file.
<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
<use xlink:href="/static/icons/entypo-sprites.svg#feather"></use>
</svg>
Strangely, this issue only arises if we use an external SVGs in <use>
.
Now we want to insert this SVG markup into some container in the page using Javascript. To do this we could directly insert the SVG markup using the innerHTML
method or first create a DOM node and insert it using the appendChild
method.
Below is the Javascript code used to do this for the demos on in this post.
(function(){
var
HTML = '<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink"><use xlink:href="/static/icons/entypo-sprites.svg#feather"></use></svg>';
var
SVG = document.createElement('template');
SVG.innerHTML = HTML;
var
button1 = document.querySelector('#demo-button1'),
button2 = document.querySelector('#demo-button2'),
button3 = document.querySelector('#demo-button3'),
button4 = document.querySelector('#demo-button4');
var
container1 = document.querySelector('#demo-container1'),
container2 = document.querySelector('#demo-container2'),
container3 = document.querySelector('#demo-container3'),
container4 = document.querySelector('#demo-container4');
button1.onclick = function(){
var svg = SVG.content.cloneNode(true).firstElementChild;
container1.appendChild(svg);
};
button2.onclick = function(){
var svg = SVG.content.cloneNode(true).firstElementChild;
container2.innerHTML += HTML;
};
button3.onclick = function(){
var svg = SVG.content.cloneNode(true).firstElementChild;
container3.appendChild(svg);
container3.innerHTML += HTML;
};
button4.onclick = function(){
var svg = SVG.content.cloneNode(true).firstElementChild;
container4.innerHTML += HTML;
container4.appendChild(svg);
};
})();
Let’s try it out. There are four demos below, where yu can click the button on top to insert the SVG into the container below it. I have styled the SVGs with a grey background and a red outline so we can see the SVG even if it does not render.
First we use the appendChild
method.
Turns out Chrome and Opera insert the element but do not actually render the SVG!
Now let’s try the innerHTML
method.
Works in every browser!
Next, just for fun, we insert two copies of the SVG first one using appendChild
and then innerHTML
.
Again, works in every browser. Both SVGs are displayed.
But, now we insert the two copies first using innerHTML
and then appendChild
.
Now, Chrome and Opera only render the first one and not the second one! However, if you try it again then, Chrome and Opera render three SVGs but not the fourth one and so on…!
This is very mystifying, and more importantly, very very annoying!