Search code examples
javascripthtmlcssweb-component

WebComponents add elements to sidebar


I am about to learn vanilla js web components. I could successfull render some elements generated by webcomponents, now I would like to give it some design and put it inside a sidebar. However I am not sure if this is webcomponents or just design problem, the elements won´t display anymoer after adding the sidebar.

Maybe you could take a look at my code and give me some hints, where I am causing the problem?

@Edit: As suggested in comment I have put it in fiddle, so you can try it out. Now I understeand the behavior even less, then In fiddle it looks kind as it should and on my local machine not.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>DiceArea</title>
    </head>
    <body>
    
    <script  type="module" src="./index.js"></script>
    </body>
    </html>
    window.addEventListener('load', () => {
        getUsers();
    });

    function getUsers() {
        const users = ["player1", "player2", "player3", "player4", "player5"];
        const nav = document.createElement("player-nav");
        nav.setAttribute("class", "sidenav")
        document.body.appendChild(nav);
    
        users.forEach(user => {
            user = document.createElement('table-user');
            nav.appendChild(user);
    
            user.addEventListener("click", () => {
                alert("lol")
            })
        })
    }

    class User extends HTMLElement {
        constructor() {
            super();
            this.shadow = this.attachShadow({mode: 'open'});
        }
    
        connectedCallback() {
            this.user();
        }
    
        user() {
            this.shadow.innerHTML = ` 
            <style>
            .sidenav {
                height: 100px;
                width: 100px;
                position: fixed;
                background-color: #0000;
                overflow-x: hidden;
                padding-top: 20px;
            }
            .avatar {
                width: 90px;
                height: 90px;
                border-radius: 10%;
            }
            </style>
           <img src="html/aavatar.png" alt="Avatar" class="avatar">`
   }
}

customElements.define("table-user", User);

https://jsfiddle.net/9bt8Lk0v/8/

And that is how it look on my local machine: enter image description here


Solution

  • At first sight I see 2 possible problems:

    • You are doing .createElement('player-nav') but never defined that Custom Element

    • You are doing nav.appendChild()
      IF nav is an element with shadowDOM, you have to do nav.shadowRoot.appendChild() because the original element content is now 'lightDOM'
      see: Difference between Light DOM and Shadow DOM

    Your code is still very traditional/oldskool DOM manipulation.

    I butchered your JSFiddle into a (quick) example showing some Web Components concepts you can play with:

    <template id=TABLE-PLAYERS>
      <style>
        :host {
          display: block;
          background: grey;
          --clickedColor: green;
        }
      </style>
      <h3>Players</h3>
    </template>
    
    <template id=PLAYER-NAV>
      <style>
        :host {
          display: block;
          background: lightgreen;
        }
    
        * {
          float: left
        }
        :host(.clicked){
          background:var(--clickedColor);
        }
        .name{
          font-size:2em;
        }
      </style>
    
      <slot name=avatar></slot>
    
      <div>
            <slot class=name name=username></slot>
      </div>
    
    </template>
    
    <table-players id=Players></table-players>