Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shadow DOM v1 CSS polyfill

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>
like image 209
Gert Cuykens Avatar asked Oct 17 '22 22:10

Gert Cuykens


1 Answers

  • 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.

like image 71
Supersharp Avatar answered Oct 23 '22 09:10

Supersharp