I tried making my own web component using the polyfill from https://github.com/webcomponents/webcomponentsjs
Here's my code:
im-list.html
<template id="im-list-temp">
<style>
:host {
list-style-type: none;
margin: 0;
padding: 0;
}
</style>
<content> </content>
</template>
<script>
var currentScript = document._currentScript || document.currentScript;
var proto = Object.create(HTMLUListElement.prototype, {
createdCallback: {
value: function() {
var doc = currentScript.ownerDocument;
var t = doc.querySelector("#im-list-temp");
var clone = doc.importNode(t.content, true);
var root = this.createShadowRoot();
root.appendChild(clone);
}
}
});
document.registerElement('im-list', {
prototype: proto,
extends: 'ul'
});
</script>
index.html
<!DOCTYPE html>
<html>
<head>
<script src="bower_components/webcomponentsjs/webcomponents.js"></script>
<link rel="import" href="./components/im-list.html" />
<title>List Test</title>
</head>
<body>
<ul is="im-list">
<li>Blubb</li>
<li>Blubb Blubb</li>
</ul>
</body>
</html>
This code works fine in Chrome (43.0.2357.81) but it doesn't work in Firefox (38.0.1 and 40.0a2) and Safari (8.0.6). In FF and Safari the <style>
is just added to the normal DOM.
I put this and other snippets on github. Feel free to fork and improve.
The problem is that webcomponets.js doesn't "fix" the style to be used on browsers that lack native ShadowDOM support. That is, it does not make the browser able to understand selectors like :host
.
The way Polymer solve it, is by rewriting the style.
So, under Polymer, this:
:host ::content div
Becomes this:
x-foo div
Therefore, to have that under a VanillaJS component, is necessary to manually do that.
Here is an snippet I use to create the Shadow Root and rewrite the styles only on browsers that use webcomponents.js instead of native Shadow DOM:
var addShadowRoot = (function () {
'use strict';
var importDoc, shimStyle;
importDoc = (document._currentScript || document.currentScript).ownerDocument;
if (window.ShadowDOMPolyfill) {
shimStyle = document.createElement('style');
document.head.insertBefore(shimStyle, document.head.firstChild);
}
return function (obj, idTemplate, tagName) {
var template, list;
obj.root = obj.createShadowRoot();
template = importDoc.getElementById(idTemplate);
obj.root.appendChild(template.content.cloneNode(true));
if (window.ShadowDOMPolyfill) {
list = obj.root.getElementsByTagName('style');
Array.prototype.forEach.call(list, function (style) {
if (!template.shimmed) {
shimStyle.innerHTML += style.innerHTML
.replace(/:host\b/gm, tagName || idTemplate)
.replace(/::shadow\b/gm, ' ')
.replace(/::content\b/gm, ' ');
}
style.parentNode.removeChild(style);
});
template.shimmed = true;
}
};
}());
Copy-paste that on your component.
Next, you need to call this function inside your createdCallback
, like:
addShadowRoot(this, "im-list-temp", "ul[is=im-list]");