javascripthtmlcssshadow-domcustom-element

CSS not working properly on Custom HTML Elements


I've been trying to make a custom HTML Element by extending the HTMLElement class. I try adding some style to it by linking a CSS file that is in the same directory as my other two files - index.html and custom.css.

Main folder

index.html:

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="nofollow" type="text/css" href=''>
</head>
 
    <body>
        <script src="./custom.js"></script>
        <smooth-button text="Smooth button" no-1 = 1 no-2 = 2></smooth-button>
    </body>
 
</html>

custom.css:

smooth-button{
    display: block;
    color: blue;
    background-color: orange;
}

custom.js:

class SmoothButton extends HTMLElement{
 
    constructor(){
        super();
        this.shadow = this.attachShadow({mode: "open"})
    }
 
    connectedCallback(){
        this.render();
    }
 
    render(){
        this.SumOfNo1AndNo2 = null;
        if(this.getAttribute("no-1")!=null && this.getAttribute("no-2")!=null){
            this.SumOfNo1AndNo2 = parseInt(this.getAttribute("no-1")) + 
            parseInt(this.getAttribute("no-2"));
        }
        else{
            console.log("Invalid attribute.")
        }
        this.shadow.innerHTML = `<button>` + this.getAttribute("text") + " " + this.SumOfNo1AndNo2   
        + "</button>"
    }
 
}
 
customElements.define("smooth-button", SmoothButton);  

With this, I get a button as expected, with the text, but the style is applied to the element as a whole and not to the elements it's made of. How can I apply the styles separately to each of its elements (just a <button> for now) with an external CSS file? I'm using external CSS because it's somehow better as I read it here.


Solution

  • Additionally to Brad's answer. One of the ways you can apply styles from the Light DOM to the Shadow DOM is with CSS Variables.

    smooth-button{
      display: block;
    
      --button-color: blue;
      --button-background-color: orange;
    }
    
    render() {
      this.shadow.innerHTML = `
        <style>
          button {
            color: var(--button-color);
            background-color: var(--button-background-color);
          }
        </style>
    
        <button>
          ${this.getAttribute("text")} ${this.SumOfNo1AndNo2}   
        </button>
      `;
    )