Consider the following:
class MyElem extends HTMLElement {};
customElements.define('my-element', MyElem);
class MyMoreSpecificElem extends MyElem {};
customElements.define('my-more-specific-element', MyMoreSpecificElem);
In the parlance of object inheritance, instances of the second class have an 'is-a' relationship with the first: a MyMoreSpecificElem
is a MyElem
.
This relationship is captured in JavaScript:
let subclassInstance = document.querySelector('my-more-specific-element');
let parentClass = document.querySelector('my-element').constructor;
subclassInstance instanceof parentClass; // true
But I can't think of any way to select all MyElem
s (including the subclass MyMoreSpecificElem) using CSS selectors. A tag selector would only get the superclass or subclass, and all of the relationship description selectors I'm aware of (e.g. ~, >) are about position in the document, not class hierarchy.
I mean, sure, I can add a CSS class in the constructor and select by that, the call to super
would ensure that even subclass instances could be selected that way. But that's gnarly. Is there a way to do this in pure CSS?
Why not have the base component class add either a className
value or an attribute that will be set for both the base component class and all of the sub-component classes. Then your CSS can be set based on this className
value or attribute.
class MyBaseEl extends HTMLElement {
connectedCallback() {
this.classList.add('my-base-el');
this.innerHTML = '<div>Base El</div>';
}
}
customElements.define('my-base-el', MyBaseEl);
class MySubEl extends MyBaseEl {
connectedCallback() {
super.connectedCallback();
this.innerHTML = '<div>Sub El</div>';
}
}
customElements.define('my-sub-el', MySubEl);
.my-base-el {
background-color: #FF0;
display: block;
outline: 1px dashed black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/1.0.22/webcomponents-lite.js"></script>
<my-base-el></my-base-el>
<my-sub-el></my-sub-el>
This uses a className
value to allow the CSS to get at all of the elements that are MyBaseEl
or a subclass.
Or like this:
class MyBaseEl extends HTMLElement {
connectedCallback() {
this.setAttribute('my-base-el', '');
this.innerHTML = '<div>Base El</div>';
}
}
customElements.define('my-base-el', MyBaseEl);
class MySubEl extends MyBaseEl {
connectedCallback() {
super.connectedCallback();
this.innerHTML = '<div>Sub El</div>';
}
}
customElements.define('my-sub-el', MySubEl);
[my-base-el] {
background-color: #FF0;
display: block;
outline: 1px dashed black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/1.0.22/webcomponents-lite.js"></script>
<my-base-el></my-base-el>
<my-sub-el></my-sub-el>
This uses an attribute to allow the CSS to get at all of the elements that are MyBaseEl
or a subclass.
UPDATE
The only other way of setting CSS for multiple element tags is to know what all of them are and make the css work for all of them like this:
my-base-el, my-sub-el, my-other-sub-el, the-third-sub-el {
background: #000;
color: #fff;
}
But, if someone else can create additional sub-classes then you would need to add to the list.
UPDATE 2
Why not just set the :host
in the base class and have it use a CSS variable for the styles you want the user to be able to change. Then everything will inherit that :host
css and display like you want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With