1

I am working with standard custom elements and self-closing custom elements.

When declared immediately adjacent to each other, they are not working entirely as I might have expected.

If I write two standard custom elements immediately adjacent to each other:

<colour-list scheme="rainbow"></colour-list>
<colour-list scheme="zebra"></colour-list>

they both display normally:

const schemes = {
  rainbowJSON : '["red", "orange", "yellow", "green", "blue", "indigo", "violet"]',
  zebraJSON : '["black", "white", "black", "white", "black"]'
}

class colourList_CustomElement extends HTMLElement {
  
  constructor() {
    super();
    this.root = this.attachShadow({mode: "open"});
  }

  connectedCallback() {

    this.root.innerHTML = `
    
      <style>
        :host {
          display: inline-block;  /* <= Because Custom elements are display:inline by default */
          contain: content;  /* <= Because this delivers an immediate performance win */
        }
        
        ul {
          margin: 0 24px 0 0;
          padding: 0;
          width: 200px;
          list-style-type: none;
        }
        
        li {
          height: 24px;
          text-align: center;
          font-weight: bold;
          text-shadow: 1px 1px rgba(0, 0, 0, 0.7);
        }
        
      </style>
      
    `;
    
    let schemeJSON = schemes[this.getAttribute('scheme') + 'JSON'];
    let colours = JSON.parse(schemeJSON);
    let colourList = document.createElement('ul');
    let listItem;
    
    for (let colour of colours) {
    
      listItem = document.createElement('li');
      let textShadow = (colour === 'black') ? 'text-shadow: 1px 1px rgba(255, 255, 255, 0.7);' : '';
      listItem.setAttribute('style', 'color: '+ colour + '; background-color: ' + colour + ';' + textShadow);
      listItem.textContent = colour;
      colourList.appendChild(listItem);

    }
    
    this.root.appendChild(colourList);
  }
}

customElements.define('colour-list', colourList_CustomElement);
<colour-list scheme="rainbow"></colour-list>
<colour-list scheme="zebra"></colour-list>

If, alternatively, I have a self-closing custom element immediately following a standard custom element:

<colour-list scheme="rainbow"></colour-list>
<colour-list scheme="zebra" />

they both also display normally:

const schemes = {
  rainbowJSON : '["red", "orange", "yellow", "green", "blue", "indigo", "violet"]',
  zebraJSON : '["black", "white", "black", "white", "black"]'
}

class colourList_CustomElement extends HTMLElement {
  
  constructor() {
    super();
    this.root = this.attachShadow({mode: "open"});
  }

  connectedCallback() {

    this.root.innerHTML = `
    
      <style>
        :host {
          display: inline-block;  /* <= Because Custom elements are display:inline by default */
          contain: content;  /* <= Because this delivers an immediate performance win */
        }
        
        ul {
          margin: 0 24px 0 0;
          padding: 0;
          width: 200px;
          list-style-type: none;
        }
        
        li {
          height: 24px;
          text-align: center;
          font-weight: bold;
          text-shadow: 1px 1px rgba(0, 0, 0, 0.7);
        }
        
      </style>
      
    `;
    
    let schemeJSON = schemes[this.getAttribute('scheme') + 'JSON'];
    let colours = JSON.parse(schemeJSON);
    let colourList = document.createElement('ul');
    let listItem;
    
    for (let colour of colours) {
    
      listItem = document.createElement('li');
      let textShadow = (colour === 'black') ? 'text-shadow: 1px 1px rgba(255, 255, 255, 0.7);' : '';
      listItem.setAttribute('style', 'color: '+ colour + '; background-color: ' + colour + ';' + textShadow);
      listItem.textContent = colour;
      colourList.appendChild(listItem);

    }
    
    this.root.appendChild(colourList);
  }
}

customElements.define('colour-list', colourList_CustomElement);
<colour-list scheme="rainbow"></colour-list>
<colour-list scheme="zebra" />

But, finally, if I have two self-closing elements, one immediately following the previous one, the second custom element does not display at all:

<colour-list scheme="rainbow" />
<colour-list scheme="zebra" />

const schemes = {
  rainbowJSON : '["red", "orange", "yellow", "green", "blue", "indigo", "violet"]',
  zebraJSON : '["black", "white", "black", "white", "black"]'
}

class colourList_CustomElement extends HTMLElement {
  
  constructor() {
    super();
    this.root = this.attachShadow({mode: "open"});
  }

  connectedCallback() {

    this.root.innerHTML = `
    
      <style>
        :host {
          display: inline-block;  /* <= Because Custom elements are display:inline by default */
          contain: content;  /* <= Because this delivers an immediate performance win */
        }
        
        ul {
          margin: 0 24px 0 0;
          padding: 0;
          width: 200px;
          list-style-type: none;
        }
        
        li {
          height: 24px;
          text-align: center;
          font-weight: bold;
          text-shadow: 1px 1px rgba(0, 0, 0, 0.7);
        }
        
      </style>
      
    `;
    
    let schemeJSON = schemes[this.getAttribute('scheme') + 'JSON'];
    let colours = JSON.parse(schemeJSON);
    let colourList = document.createElement('ul');
    let listItem;
    
    for (let colour of colours) {
    
      listItem = document.createElement('li');
      let textShadow = (colour === 'black') ? 'text-shadow: 1px 1px rgba(255, 255, 255, 0.7);' : '';
      listItem.setAttribute('style', 'color: '+ colour + '; background-color: ' + colour + ';' + textShadow);
      listItem.textContent = colour;
      colourList.appendChild(listItem);

    }
    
    this.root.appendChild(colourList);
  }
}

customElements.define('colour-list', colourList_CustomElement);
<colour-list scheme="rainbow" />
<colour-list scheme="zebra" />

It's not clear to me why in the last example both elements are not displaying.

Rounin
  • 21,349
  • 4
  • 53
  • 69
  • 2
    Autonomous Custom Elements can **not** be self closing. Only Customized Built-In Elements (like IMG) can... but Apple refuses to implement Customized Built-In elements. – Danny '365CSI' Engelman Oct 19 '20 at 18:40
  • 1
    Here you go: https://github.com/w3c/webcomponents/issues/624 **rniwa** is Apple, **annevk** is Mozilla, **hayatoito** is Google – Danny '365CSI' Engelman Oct 19 '20 at 18:54
  • 2
    There are no custom self-closing elements. Self-closing (void) elements are [precisely defined exceptions to the normal parsing algorithm](https://stackoverflow.com/a/3558200/1048572) for `img`, `br`, `meta`, `input` and a few others. Always close your elements explicitly. What you've got are two nested elements with missing closing tags. – Bergi Oct 19 '20 at 18:57
  • That's a great link @Danny'365CSI'Engelman - thanks very much. I share the enthusiasm of many of the participants in that thread for self-closing custom elements. I also get why void custom elements would be hard to parse, but surely not self-closing custom elements (?) The regex for a self-closing custom element would be: `^\$`. – Rounin Oct 19 '20 at 20:03

1 Answers1

1

continuing from comments above...

Note that you can create Unknown Elements (creating a FOUC) which you can querySelect, process into what you want and then remove from the DOM

<my-elements>
  <green id=foo />
  <red id=bar />
  Bye Bye World
</my-elements>

Hello World!


<script>
  customElements.define('my-elements', class extends HTMLElement {
    connectedCallback() {
      setTimeout(() => {
        this.append(...[...this.querySelectorAll("*")].map(node => {
          console.log(node.outerHTML);
          let div = document.createElement("div");
          div.style.color = node.nodeName;
          div.innerHTML = `${node.id} ${node.nodeName}`;
          node.remove();
          return div;
        }));
      });
    }
  });
</script>
Danny '365CSI' Engelman
  • 6,903
  • 1
  • 16
  • 29
  • Thanks for this, @Danny'365CSI'Engelman. If you're happy to copy and paste your very useful comments / link from above into your question, that will make it even better. Thank you. – Rounin Oct 19 '20 at 20:05