I see examples of using SVG elements within a custom element (such as here), but so far I haven't been able to figure out how to define a custom element to go inside an SVG element.
I've tried the following, and while the template content does appear in the web inspector, the circle doesn't appear visually.
<polymer-element name=my-element noscript>
<template>
<circle cx=10 cy=10 r=5 />
</template>
</polymer-element>
<svg>
<my-element />
</svg>
Is there a trick to getting custom elements to work within SVG elements?
Unfortunately, you can't do this. Elements within the SVG namespace need to be within <svg>
. Creating <my-element>
creates a custom element that inherits from HTMLElement
.
You can however, include <svg>
in a custom element: http://jsbin.com/EXOWUFu/2/edit
Also, don't forget that custom elements cannot be self closing. So in your example, <my-element />
-> <my-element></<my-element>
. This is because the HTML spec only allows a few elements to be self-closing.
Update
Turns out you can embed a custom element inside <svg>
using <foreignObject>
.
Demo: http://jsbin.com/hareyowi/1/edit
<foreignObject width="100" height="100">
<x-foo></x-foo>
</foreignObject>
According to this open ticket (https://github.com/Polymer/polymer/issues/1976), you actually CAN have a template element nested inside an svg element. The fix I will link to below is a port of the code from 0.5. The issue is described in detail here and in the open ticket, so no need to go over it again.
Important:
If you would like to indicate to Google and the polymer team that this is indeed an important feature, please make sure you leave a comment on the ticket.
Snippet: https://gist.github.com/bendavis78/15528ca2f501c44f2fa4
foo-svg.css
foo-svg svg {
border: 2px solid yellowgreen;
fill: transparent;
height: 400px;
width: 400px;
}
foo-svg.html
<dom-module id="foo-svg">
<link rel="stylesheet" href="foo-svg.css"/>
<template>
<svg class="clock" version="1.1" xmlns="http://www.w3.org/2000/svg">
<template is="dom-repeat" items="{{positions}}" as="cx">
<circle cx$="{{cx}}" cy="25" r="25" stroke="black" />
</template>
</svg>
</template>
<script src="foo-svg.js"></script>
foo-svg.js
(function () {
// START HACK
var doc = document.currentScript.ownerDocument;
var root = doc.querySelector('dom-module > template').content;
var templates = root.querySelectorAll('svg template');
var el, template, attribs, attrib, count, child, content;
for (var i=0; i<templates.length; i++) {
el = templates[i];
template = el.ownerDocument.createElement('template');
el.parentNode.insertBefore(template, el);
attribs = el.attributes;
count = attribs.length;
while (count-- > 0) {
attrib = attribs[count];
template.setAttribute(attrib.name, attrib.value);
el.removeAttribute(attrib.name);
}
el.parentNode.removeChild(el);
content = template.content;
while ((child = el.firstChild)) {
content.appendChild(child);
}
}
// END HACK
Polymer({
is: 'foo-svg',
properties: {
paths: {
type: Array,
value: []
}
},
ready () {
this.positions = [0, 100, 200, 300];
}
});
})();
The Polymer FAQ shows that a template can be used within an <svg>
element:
<svg>
<template repeat="{{l in lights}}">
<circle cx="100" cy="{{l.cy}}" r="50" fill="{{l.color}}"/>
</template>
</svg>
https://www.polymer-project.org/0.5/resources/faq.html#templateinsvg
Indeed this works in Polymer 0.5! But it does not work in Polymer 0.9 or 1.0.
In changed Polymer 1.0 syntax it looks like this:
<svg>
<template is="dom-repeat" items="{{lights}}">
<circle cx="100" cy$="{{item.cy}}" r="50" fill$="{{item.color}}"/>
</template>
</svg>
The element is not rendered and the browser console shows:
TypeError: node is undefined in polymer.html:28
The error refers to Polymer's _parseNodeAnnotations()
function.
That the FAQ example works in 0.5 apparently shows there is no reason why SVG should not work in Web Components or Polymer in principle. This let me hope the Polymer team will fix that soon.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With