Search code examples
csshtmlweb-componentshadow-domcustom-element

Why do pseudoclasses on the host element have to be inside of the host function?


I do not understand why pseudo classes like :focus-within need to be within the :host() function brackets when acting on the host itself. Why can it not be :host:focus-within div? It's even more weird that it works on :host inside of another :host().

class MyElementFail extends HTMLElement {

	constructor(...args) {
		super(...args)

		this.attachShadow({mode: 'open'}).innerHTML = `
		<style>
    :host{
      display: block;
      padding: 20px;
      background-color: salmon;
    }
    :host div{
      background-color: white;
    }
    /*This part is different:*/
		:host:focus-within div{
			background-color: green;
		}
		</style>
    <input type="text" value="click in here"/>
		<div>
    Change to green
		</div>`
	}
}
window.customElements.define('my-element-fail', MyElementFail);


class MyElement extends HTMLElement {

	constructor(...args) {
		super(...args)

		this.attachShadow({mode: 'open'}).innerHTML = `
		<style>
    :host{
      display: block;
      padding: 20px;
      background-color: salmon;
    }
    :host div{
      background-color: white;
    }
    /*This part is different:*/
		:host(my-element:focus-within) div{
			background-color: green;
		}
		</style>
    <input type="text" value="click in here"/>
		<div>
    Change to green
		</div>`
	}
}
window.customElements.define('my-element', MyElement);


class MyElementTwo extends HTMLElement {

	constructor(...args) {
		super(...args)

		this.attachShadow({mode: 'open'}).innerHTML = `
		<style>
    :host{
      display: block;
      padding: 20px;
      background-color: salmon;
    }
    :host div{
      background-color: white;
    }
    /*This part is different:*/
		:host(:host:focus-within) div{
			background-color: green;
		}
		</style>
    <input type="text" value="click in here"/>
		<div>
    Change to green
		</div>`
	}
}
window.customElements.define('my-element-two', MyElementTwo);
No Good:
<my-element-fail></my-element-fail>
Good:
<my-element></my-element>
Good also:
<my-element-two></my-element-two>

Essentially, why does,

:host(:host:focus-within) div{ work, and

:host(my-element:focus-within) div{ work, but

:host:focus-within div{ not work?


Solution

  • :host is only to indicate the host element of the shadowDOM.

    :host(.something) indicated the host with a class of .something.

    You can not use :host.something you must use the parenthesis.

    :host() is not a function. It is just how to select a :host with additional specificity.

    class MyElement extends HTMLElement {
    	constructor() {
    		super();
    		this.attachShadow({mode: 'open'}).innerHTML = `
    		<style>
        :host{
          display: block;
          padding: 20px;
          background-color: salmon;
        }
    
        div{
          background-color: white;
        }
    
        :host(:focus-within) div{
    			background-color: green;
    		}
    		</style>
        <input type="text" value="click in here"/>
    		<div>Change to green</div>`;
    	}
    }
    window.customElements.define('my-element', MyElement);
    <my-element></my-element>