5

https://developers.google.com/web/fundamentals/getting-started/primers/shadowdom

This got me all excited I could write my own custom webpage from scratch without polymer.

Only to find out css :host for example is not working in Edge and FireFox. I can deal without html import for now until w3c figured out what they want to do with es6 modules, but each browser having their own half implemented Shadow DOM version without css is pushing my buttons.

So I still need a full polymer stack to have webcomponents in all browsers.

<script src="../webcomponentsjs/webcomponents-lite.js"></script>

<link rel="import" href="../hello-world.html">

<hello-world>Hello World Polymer 2.x</hello-world>

Does anybody know how to polyfill Edge and FireFox to have a actually Shadow DOM, not a native Shadow DOM that's pretending to be one?

This is what I tried, but I can't figure out how to tell Edge and FireFox to put their Shadow wannabe somewhere else and use the shadydom/shadycss.

https://jsbin.com/quvozo

<!DOCTYPE html>
<html>

<head>
  <title>Components</title>
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0"/>
</head>

<body>
  <hello-world>Hello World ES2015</hello-world>
  <script>
    function loadScript(src, main) {
      return new Promise(function(resolve, reject) {
        const script = document.createElement('script');
        script.async = true;
        script.src = src;
        script.onload = resolve;
        script.onerror = reject;
        document.head.appendChild(script);
      });
    }
    let polyfilled = false;
    const loadPromises = [];
    if (!('customElements' in window)) {
      loadPromises.push(loadScript('https://raw.githubusercontent.com/webcomponents/custom-elements/master/custom-elements.min.js'));
    }
    if (!HTMLElement.prototype.attachShadow) {
      polyfilled = true
      loadPromises.push(loadScript('https://raw.githubusercontent.com/webcomponents/shadydom/master/shadydom.min.js'));
      loadPromises.push(loadScript('https://raw.githubusercontent.com/webcomponents/shadycss/master/shadycss.min.js'));
    }
    Promise.all(loadPromises)
      .then(e => console.log(`polyfilled ${polyfilled}`))
      .then(e => {
        class HelloWorld extends HTMLElement {
          constructor() {
            super()
            this.template = document.createElement('template')
            this.template.innerHTML = `
              <style>
                :host {
                  display: block;
                  box-sizing: border-box;
                  border: 1px solid red;
                  margin-top: 10px;
                  padding: 0px 5px;
                }
              </style>
              <p>Test <slot></slot></p>
            `
            if (polyfilled) ShadyCSS.prepareTemplate(this.template, 'hello-world');
          }
          connectedCallback() {
            const shadowRoot = this.attachShadow({ mode: 'open' })
            shadowRoot.appendChild(this.template.content.cloneNode(true))
            if (polyfilled) ShadyCSS.applyStyle(this);
          }
        }
        customElements.define('hello-world', HelloWorld)
      })
  </script>
</body>

</html>
Supersharp
  • 29,002
  • 9
  • 92
  • 134
Gert Cuykens
  • 6,845
  • 13
  • 50
  • 84
  • 1
    This was an entertaining read, thanks. In fairness, the standards (yes, plural) are still far from mature and Microsoft Edge is still relatively new. Microsoft has already announced that [they'll be taking steps to implement web components](https://blogs.windows.com/msedgedev/2015/07/15/microsoft-edge-and-web-components) but it *will* take a while. It doesn't help that Shadow DOM itself went through a complete rewrite in the first place. It's not easy for the browser vendors. – BoltClock Nov 15 '16 at 04:42
  • I understand and part of me is glad they are doing their best, but my frustration aside I was hoping somebody could help me how to use the polyfill shadycss corectly from https://github.com/webcomponents I know its possible because polymer is doing it. I just want to know how exactly because the article doesn't take a partly native shadow dom into account. Thanks – Gert Cuykens Nov 15 '16 at 05:37

1 Answers1

3
  • Shadow DOM polyfill won't create a real Shadow DOM but normal DOM elements,
  • The Custom Elements specification won't allow you to add elements in the normal DOM tree in constructor(),

Therefore, you should attach the fake Shadow DOM afterwards, that is inside the connectedCallback() method, instead of inside the constructor() method.

The ShadyCSS polyfill works fine with Edge and Firefox.

Supersharp
  • 29,002
  • 9
  • 92
  • 134
  • ok thanks I modified it again, but Edge still doesn't style like the others. Anyway if you see nothing else wrong then at least I know its not my fault. – Gert Cuykens Nov 15 '16 at 11:04
  • did you test it with firefox? what are the logged messages? did you try with plain JS? Why Hello-A / Hello-B? Altough I never tested the polyfill with Edge I think it's rather your fault :-) – Supersharp Nov 15 '16 at 11:40
  • Because import's are not supported I needed to make sure something like requirejs could do all the importing for me. I tested it if module Hello-B could find Hello-A. Your are right I can make it a bit simpler, will try to make a single page instead. But I am pretty sure it's going to be the same result :P Note that it's only the style `:host` that is not working in Edge, basically the element html without the css get stamped out correctly – Gert Cuykens Nov 15 '16 at 17:19
  • https://jsbin.com/qekadi made a better example :D works in chrome and safari, but edge doesn't style it – Gert Cuykens Nov 15 '16 at 22:05
  • 1
    OK the problem is that the ShadyCSS API is never called because `!HTMLElement.prototype.attachShadow` is always false when you evaluate it, for the ShadowDOM polyfill has already added the method. You should set a variable before. jsbin.com/luzikedipi – Supersharp Nov 16 '16 at 08:18
  • hmm my firefox beta (android mobile) and edge (desktop) still has no red border using your version. But what you said is 100% correct. – Gert Cuykens Nov 16 '16 at 09:00
  • 1
    It works for me with Edge with local polyfill. Anyway the workaround is to not use ShadyCSS and duplicate the `:host` CSS block to `hello-world`. That's what ShadyCSS does under the hood. – Supersharp Nov 16 '16 at 13:15
  • 1
    Confirmed thanks, if i do `:host, hello-world {...}` in my template its working. I am still pointing fingers to Edge and FireFox though for not doing the `:host` thing :P – Gert Cuykens Nov 16 '16 at 20:48