I've been experimenting with HTML5 and SVG; and I'm very new to JavaScript and web development, so there's probably something I'm missing. I am trying to create reusable web ponents, leveraging some of the new features, such as HTML Imports, Shadow DOM, and extending existing web elements. I have two html files:
test.html
<html>
<head>
<title>Test HTML5</title>
</head>
<body>
<link rel="import" href="Elements/tank.html">
<svg width="100%"
viewBox="0 0 500 500"
style="border: solid; border-width: thin; stroke-width: 2;">
<polyline points="0,300 100,300 100,100 250,100 250,150 500,150"
style="fill:none;stroke:black;stroke-width:3"
onclick="window.alert('you clicked line')" />
<svg is="my-tank" x="200" y="350" width="50" height="50"></svg>
</svg>
</body>
</html>
tank.html
<html>
<body>
<template id="tank">
<rect fill="red" width="50" height="50"></rect>
</template>
<script type="text/javascript">
var tankElement = document.currentScript.ownerDocument.querySelector('#tank');
document.registerElement('my-tank', {
prototype: Object.create(SVGSVGElement.prototype, {
createdCallback: {
value: function () {
var root = this.createShadowRoot();
//Works
root.innerHTML = tankElement.innerHTML;
//Doesn't work
//var tankTemplate = document.importNode(tankElement.content, true);
//root.appendChild(tankTemplate);
}
}
}),
extends: 'svg'
});
</script>
</body>
</html>
The code under the //Works
ment draws a red rectangle where I'd expect in the SVG drawable space. The code under //Doesn't work
doesn't draw anything or yield any error.
Screenshot of //Works
:
Screenshot of //Doesn't work
:
I've been testing with Opera 41.0.
I've been experimenting with HTML5 and SVG; and I'm very new to JavaScript and web development, so there's probably something I'm missing. I am trying to create reusable web ponents, leveraging some of the new features, such as HTML Imports, Shadow DOM, and extending existing web elements. I have two html files:
test.html
<html>
<head>
<title>Test HTML5</title>
</head>
<body>
<link rel="import" href="Elements/tank.html">
<svg width="100%"
viewBox="0 0 500 500"
style="border: solid; border-width: thin; stroke-width: 2;">
<polyline points="0,300 100,300 100,100 250,100 250,150 500,150"
style="fill:none;stroke:black;stroke-width:3"
onclick="window.alert('you clicked line')" />
<svg is="my-tank" x="200" y="350" width="50" height="50"></svg>
</svg>
</body>
</html>
tank.html
<html>
<body>
<template id="tank">
<rect fill="red" width="50" height="50"></rect>
</template>
<script type="text/javascript">
var tankElement = document.currentScript.ownerDocument.querySelector('#tank');
document.registerElement('my-tank', {
prototype: Object.create(SVGSVGElement.prototype, {
createdCallback: {
value: function () {
var root = this.createShadowRoot();
//Works
root.innerHTML = tankElement.innerHTML;
//Doesn't work
//var tankTemplate = document.importNode(tankElement.content, true);
//root.appendChild(tankTemplate);
}
}
}),
extends: 'svg'
});
</script>
</body>
</html>
The code under the //Works
ment draws a red rectangle where I'd expect in the SVG drawable space. The code under //Doesn't work
doesn't draw anything or yield any error.
Screenshot of //Works
:
Screenshot of //Doesn't work
:
I've been testing with Opera 41.0.
Share Improve this question edited Jun 20, 2020 at 9:12 CommunityBot 11 silver badge asked Nov 25, 2016 at 18:00 Justin HuskicJustin Huskic 931 silver badge7 bronze badges2 Answers
Reset to default 3You cannot do this, since svg
cannot be a shadow host. Only a limited number of elements can be a shadow host:
article
, aside
, blockquote
, body
, div
, footer
, h1
, h2
, h3
, h4
, h5
, h6
, header
, main
, nav
, p
, section
, span
.
So not only svg
, but also others like input
or textarea
cannot have shadow-doms (I'm talking about Shadow-DOM v1).
See the definition of the attachShadow
for the details: https://dom.spec.whatwg/#dom-element-attachshadow
Note also that:
SVGSVGElement
does not implementHTMLElement
.- Also heard something about SVG's already containing a shadow-dom in their implementation, and with Custom Elements v1 you may have only one shadow-dom (see here: http://hayato.io/2016/shadowdomv1/).
Why don't you create instead a regular custom-element, which may contain <svg>
elements inside its shadow-dom?
It's because in your <template>
, the <rect>
element is not inside a <svg>
tag, so it is not recognized as a SVGRectElement
but as an HTMLUnknownElement
instead.
To make it work, just add the <svg>
tag around:
<template id="tank">
<svg>
<rect fill="red" width="50" height="50"></rect>
</svg>
</template>
Now you can import the element using importNode()
, or cloneNode()
:
//Works
var rect = tankElement.content.querySelector('rect').cloneNode();
root.appendChild(rect);
Update Importing mutliple SVG Elements
Put elements in <g>
:
<template id="tank">
<svg>
<g>
<rect fill="red" width="50" height="50"></rect>
<rect fill="blue" width="25" height="50"></rect>
</g>
</svg>
</template>
Clone <g>
with its content:
var g = tankElement.content.querySelector('g').cloneNode(true);
root.appendChild(g);