I have been trying to use CSS custom properties within a custom element, like so:
function tpl(raw){
const template = document.createElement('template');
template.innerHTML = raw;
return template;
}
const templateNode = tpl`
<style>
:root {
--default-text-color: red; // IDE squiggles
}
p { color: var(--default-text-color); }
</style>
<p>Test</p>
`
class MyElement extends HTMLElement {
constructor() {
super();
const sd = this.attachShadow({ mode: 'open' });
sd.appendChild(templateNode.content.cloneNode(true))
}
connectedCallback(){
console.log('my-element connected')
}
}
customElements.define('my-element', MyElement)
The custom property: --default-text-color
doesn't seem to be recognized by IDE and it is not resolved by the browser.
So apparently I am missing some crucial bit of info as to why the above code is not supposed to work. Can anyone explain?
NB. I am aware of Constructable StyleSheets and its adoptedStyleSheets
member, but it only seems to be a proposed solution at this moment, not fully supported by all browsers yet. I am hoping to find a solution which works in all browsers that support css custom properties and custom elements.
As mentioned by Myf in the comments, your use of :root
instead of :host
is your problem.
You can use :root
at document level (or any CSS selector),
because CSS properties cascade into shadowDOM.
(unrelated) You are also overcomplicating code; but you can't be blamed,
all blogs and even MDN documentation show bloated code
customElements.define('my-element', class extends HTMLElement {
constructor() {
super() // sets AND returns 'this' scope
.attachShadow({ mode: 'open'}) // sets AND returns 'this.shadowRoot'
.innerHTML = `<style>
:host{ --textcolor: green }
p { color: var(--textcolor,red); background: var(--bgcolor,grey) }
</style>
<h1>Hello Web Component</h1>`
}
})
:root {
--bgcolor: lightgreen;
}
<my-element></my-element>
https://stackoverflow.com/revisions/68934167/4
Note if you do it that way, --textcolor
is no longer inheritable from an ancestor element that is above the custom element to be styled.
Placing your vars in :root
is one way to keep them inheritable, but not ideal for code inside a custom element.
Mapping them to "internal" vars is another way we can do this so that we can keep properties inheritable:
:host {
--textcolor--: var(--textcolor, red);
}
Then use --textcolor--
(using a convention of two trailing slashes to mark a property as "internal") where the style is needed:
p {
color: var(--textcolor--);
}
Now --textcolor
is inheritable because it will not be overriden by a value on :host
.