12

I'm trying to style a child element of a shadow DOM root.
This defines a custom element called element-el, which have a span class-named 'x' with the letter x in it, which I want, for the state of the matter, to be red.

class El extends HTMLElement {
    constructor() {
        super();
        var shadow = this.attachShadow({mode:'open'});
        shadow.innerHTML = '<span class="x">X</span>';
    }
}
customElements.define ('element-el',El);

I've tried those CSS styles:

element-el::slotted(.x) {
  color:red;
}
element-el::host .x {
  color:red;
}
element-el:host .x {
  color:red;
}
element-el::shadow .x {
  color:red;
}
element-el /deep/ .x {
  color: red;
}
element-el::content .x {
  color:red;
}

The X does not become red. I'm using Chrome 56, which is supposed to support this...

I want to style it without putting a style element inside the shadow DOM.
Here is a codepen: http://codepen.io/anon/pen/OpRLVG?editors=1111

EDIT:
This article suggests that it is possible to style shadow children from an external CSS file -- are they simply wrong?

Supersharp
  • 29,002
  • 9
  • 92
  • 134
Yuval A.
  • 5,849
  • 11
  • 51
  • 63
  • **For Angular 4.3.0+ till now (Angular 12.x), see: [How to style child components from parent?](https://stackoverflow.com/a/36528769/8740349)** – Top-Master Oct 28 '21 at 16:52

3 Answers3

1

Apparently the problem is the fact that you are trying to use the global CSS to style the shadow tree elements.

You can use the :host pseudo selector, however in order to do so you will have to place the style inside the shadow tree content.

Make the following changes in your javascript:

class El extends HTMLElement {

    constructor() {
        super();
        var shadow = this.attachShadow({mode:'open'});
        var innerHTML = '';
        innerHTML += '<style>';
        innerHTML += ':host(element-el.red) span {color: red}';
        innerHTML += ':host(element-el.green) span {color: green}';
        innerHTML += ':host(element-el.blue) span {color: blue}';
        innerHTML += '</style>';      
        innerHTML += '<span class="x">X</span>';      
        shadow.innerHTML = innerHTML;
    }

}

customElements.define ('element-el',El);

Check a functional example in your updated codepen.

Romulo
  • 4,896
  • 2
  • 19
  • 28
  • Thanks for the answer. I was relaying on this: https://developer.mozilla.org/en-US/docs/Web/Web_Components/Custom_Elements , when thinking I can style the shadow DOM children from within an external CSS (see 'CSS file' in 'Example' part) - are they simply wrong in the article? – Yuval A. Mar 06 '17 at 10:40
  • Check the example they provide at: https://mdn.mozillademos.org/en-US/docs/Web/Web_Components/Custom_Elements$samples/Example. Both CSS declarations using the pseudo-selector `::slotted` aren´t working in Chrome. – Romulo Mar 06 '17 at 12:38
0

A simple solution is to define the x class in the Shadow DOM:

class El extends HTMLElement {
    constructor() {
        super()
        this.attachShadow({mode:'open'})
            .innerHTML = `
               <style>
                  .x { color: red } 
               </style>
               <span class="x">X</span>`
    }
}
customElements.define ('element-el',El)
<element-el></element-el>

Note: Because of Shadow DOM's style encapsulation, you'll always need to put a <style> element in the Shadow DOM, whether using Romulo's :host solution, a direct class declaration (see above), or an external stylesheet.

Of course if you use an inherited CSS property (like color) that will aplly to all your shadow DOM content, you can just use normal CSS:

class El extends HTMLElement {
    constructor() {
        super();
        var shadow = this.attachShadow({mode:'open'});
        shadow.innerHTML = '<span class="x">X</span>';
    }
}
customElements.define ('element-el',El);
element-el {
    color: red;
}
<element-el></element-el>   
Supersharp
  • 29,002
  • 9
  • 92
  • 134
  • Thanks for the answer. I was relaying on this: https://developer.mozilla.org/en-US/docs/Web/Web_Components/Custom_Elements , when thinking I can style the shadow DOM children from within an external CSS (see 'CSS file' in 'Example' part) - are they simply wrong in the article? – Yuval A. Mar 06 '17 at 10:39
  • 2
    @YuvalA. yes they are wrong with the `::slotted` styles. They don't work because they are not at the right place (in a shadow DOM's – Supersharp Mar 06 '17 at 10:49
-1

This may help someone else in a similar situation.

In my case I have:

<svg class="icon">
    <use xlink:href="#my-icon"></use>
</svg>

and to access the rendered icon in #shadow-root, I use:

.icon use {
  fill: #f80;
}
A. D'Alfonso
  • 759
  • 11
  • 20