0

I can't manage to change a css variable (--color) because the shadowRoot querySelector won't return :host or html

<style>
    :host {display: block;
        --color: ${this.color};
    }
    .colored {
        color: var(--color);
    }
</style>

This breaks (querySelector returns null)

this.shadowRoot.querySelector(':host').style.setProperty('--color', value);

This changes the color but is not want I want

this.shadowRoot.querySelector('.colored').style.setProperty('color', value); 

And finally, this attempt does the trick, but it will only work as long as :host is the first rule and it is in the first stylesheet.

this.shadowRoot.styleSheets[0].rules[0].style.setProperty('--color', value);

<!DOCTYPE html>

<body>
    <my-element></my-element>
    <script>
        class MyElement extends HTMLElement {
            constructor() {
                super();
                this._color = "green";
                this._shadowRoot = this.attachShadow({ mode: "open" });
                this._shadowRoot.innerHTML = '';
                this._shadowRoot.appendChild(this.template().content.cloneNode(true));
            }
            template() {
                const template = document.createElement("template");
                template.innerHTML = `
<style>
    :host {display: block;
        --color: ${this.color};
    }
    .colored {
        color: var(--color);
    }
</style>
            <p>The color will change in 2 seconds: <span id="color" class="colored">${this.color}</span></p>
        `;
                return template;
            }
            get color() {
                return this._color;
            }
            set color(value) {
                this._color = value;
                this.shadowRoot.getElementById('color').innerHTML = value;
                // ▼  Uncomment below. Cannot change --color variable; selector returns null
                // this.shadowRoot.querySelector(':host').setProperty('--color', value); 

                // ▼ This works but is not what I want. I need to change the variable
                 //this.shadowRoot.querySelector('.colored').style.setProperty('color', value); 

                 // ▼ This is subject to the firts stylesheet and :host being first rule
                 this.shadowRoot.styleSheets[0].rules[0].style.setProperty('--color', value);
            }

        }
        customElements.define("my-element", MyElement);
        setTimeout(() => {
            document.querySelector('my-element').color = 'blue';
        }, 2000);
    </script>
</body>

</html>

Thanks!

daniel p
  • 741
  • 7
  • 12

1 Answers1

3

:host refers to your <my-element>

So set properties on your my-element with: this.style.setProperty('--color', value);

<my-element></my-element>
<script>
  customElements.define("my-element", class extends HTMLElement {
    constructor() {
      super()
        .attachShadow({mode: "open"})
        .innerHTML = `
            <style>
                :host {display: block;
                    --color: red;
                }
                .colored {
                    color: var(--color);
                }
            </style>
            <p>The color will change in 2 seconds: <span id="color" class="colored">${this.color}</span></p>`;
       this.color = "green";
    }
    get color() {
      return this._color;
    }
    set color(value) {
      this._color = value;
      this.shadowRoot.getElementById('color').innerHTML = value;
      this.style.setProperty('--color', value); 
    }
  });
  setTimeout(() => {
    document.querySelector('my-element').color = 'blue';
  }, 2000);
</script>
Danny '365CSI' Engelman
  • 16,526
  • 2
  • 32
  • 49