S R T B H P N
Tests.html

Test Photo Element

Implements W3C/Google webcomponent

Works with FireFox, Chrome, Safari. Edge rendering has problem with innerHTML.
Figure 1. ThreadPool
This is how this page uses the PhotoSizer Element:
    <photo-block src="Pictures/ThreadPool.JPG" width="300" class="photoBlock">
      <span style="font-family:'Comic Sans MS'">Figure 1. a caption</span>
    </photo-block>
And this is how this pages styles the PhotoSizer Element:
    #github photo-block {
      --border:1px solid black;
      --box-shadow: 3px 3px 5px #999;
    }
    /* uncomment .photoBlock to use this class */
    /*#github .photoBlock {
      --background-color: #efe;
      --font-family:Comic Sans MS;
      --font-weight: Bold;
      --border: 3px solid darkgreen;
    }*/
View page source to see all the details.
Here's the component code:
  <script>
    /* custom webcomponent - CodeBlock*/

    class PhotoBlock extends HTMLElement {
      constructor() {
        super();
        const shadowRoot = this.attachShadow({ mode: 'open' });
        shadowRoot.innerHTML =
          `
            <style>
              #cont {
                display:flex;
                padding: var(--padding);
              }
              #wrapper {
                width:min-content;
                padding:10px;
                margin: 20px;
                background-color: var(--background-color);
                color: var(--color);
                box-shadow: var(--box-shadow);
                font-family: var(--font-family);
                font-size: var(--font-size);
                font-weight: var(--font-weight);
                border: var(--border);
                user-select:none;
                -webkit-user-select:none;
                -moz-user-select:none;
                -ms-user-select:none;
              }
              #caption {
              text-align:center;
              }
            </style>
            <div id="cont">
              <slot></slot>
              <div id="wrapper">
                <img />
                <div id="caption"></div>
              </div>
            </div>`;
      }
      connectedCallback() {
        this.url = this.getAttribute('src');
        this.imgElem = this.shadowRoot.querySelector('img');
        this.imgElem.setAttribute('src', this.url);
        this.width = this.getAttribute('width');
        if (isDefined(this.width))
          this.imgElem.setAttribute('width', this.width);
        this.height = this.getAttribute('height');
        if (isDefined(this.height))
          this.imgElem.setAttribute(this.height);
        this.caption = this.shadowRoot.querySelector('#caption');
        if (isDefined(this.caption))
          this.caption.innerHTML = this.innerHTML;
        this.innerHTML = "";
      }
    }
    /*--------------------------------------------------------------------------- 
     * This listener is added because of a component lifecycle issue with chrome
     * See first reference, below.
     */
    document.addEventListener('DOMContentLoaded', function () {
      window.customElements.define('photo-block', PhotoBlock);
    }); 
    /* 
     * The listener, above, will be removed and replaced with this when chrome
     * component lifecycle is fixed.
     * 
     * window.customElements.define('photo-block', PhotoBlock); 
     */
  </script>


References:

  1. Issue with Chrome loading innerHTML
  2. polyfills CDN
  3. customelements - google.com
  4. shadowdom - google.com
  5. webcomponents - htm5rocks.com
  6. attributes & properties - alligator.io
  7. styling webcomponent - css-tricks.com
  8. encapsulating style and structure - css-tricks.com
  9. creating custom component from scratch - css-tricks.com
  10. Using custom elements - mozilla.org
  11. introduction to webcomponents - webcomponents.org
  12. build web components - dev.to
  13. tutorial - robinwieruch.de
  14. introduction - grapecity.com