Search code examples
javascriptcssweb-componentcustom-elementcss-variables

How to provide a fallback CSS-value within a custom element?


I have a custom web-component which is basically an SVG-Icon:

<custom-icon>
    <svg>{svg-stuff}</svg>
</custom-icon>

I want to be able to change it's size by applying CSS like so:

custom-icon {
    width: 20px;
}

But I also would like to have a fallback default value when no CSS is applied. However, when I inline some CSS like <custom-icon style="width:15px"> it just overwrites all CSS I apply afterwards. How can I have the default "15px" only apply if there is no custom CSS?

MWE:

class CustomIcon extends HTMLElement {
  constructor() {
    super();
    
    let size = "100px"
    
    this.style.height = size;
    this.style.width = size;
    
    this.style.background = "firebrick"
    this.style.display = "block"
  }
}

window.customElements.define('custom-icon', CustomIcon);
custom-icon {
  --icon-size: 50px;
  height: var(--icon-size);
  width: var(--icon-size);
}
<custom-icon />


Solution

  • If the content of your custom element is encapsulated in a Shadow DOM, which is a recommended practice, you can use the :host pseudo-class to define a default style.

    Then if you define a global style for your custom element it will override the one defined with :host.

    customElements.define( 'custom-icon', class extends HTMLElement {
      constructor() {
        super()
        let size = 100
        this.attachShadow( { mode: 'open' } )
            .innerHTML = `
              <style>
                :host {
                   display: inline-block ;
                   height: ${size}px ;
                   width: ${size}px ;
                   background-color: firebrick ; 
                   color: white;
                }
              </style>
              <slot></slot>`
      }
    } )
    custom-icon#i1 {
      --icon-size: 50px;
      height: var(--icon-size);
      width: var(--icon-size);
    }
    <custom-icon id="i1">sized</custom-icon>
    <hr>
    <custom-icon>default</custom-icon>