Styling element in shadow dom

Viewed 318

I have two custom elements

<desktop-canvas id="desktop">
  #shadow-root (open) 
    <desktop-window>
    </desktop-window>
<desktop-canvas>

I'm trying to style <desktop-window> like so:

#desktop::shadow desktop-window {
  background-color: red;
  padding: 25px;
  margin: 25px;
  display: block;
}

But desktop-window dosen't receive the style. What am I doing wrong? The same syntax seems to be working in this codepen (not by me): https://codepen.io/matt-west/pen/FtmBL

1 Answers

As announced here...

Starting in Chrome 63, you cannot use the shadow-piercing selectors ::shadow and /deep/ to style content inside of a shadow root.

According to that page you are only affected if you use Shadow DOM v0 components. You either use the shady DOM polyfill, switch to Shadow DOM v1 components or place the styles inside the component and use :host:

var XProductProto = Object.create(HTMLElement.prototype);

XProductProto.createdCallback = function() {
  var shadow = this.createShadowRoot();

  var img = document.createElement('img');
  img.alt = this.getAttribute('data-name');
  img.src = this.getAttribute('data-img');
  img.width = '150';
  img.height = '150';
  img.className = 'product-img';

  shadow.appendChild(img);

  img.addEventListener('click', function(e) {
    window.location = this.getAttribute('data-url');
  });

  var link = document.createElement('a');
  link.innerText = this.getAttribute('data-name');
  link.href = this.getAttribute('data-url');
  link.className = 'product-name';

  shadow.appendChild(link);
  var styleEl = document.createElement('style');
  styleEl.innerHTML = `
:host .product-img {
  cursor: pointer;
  background: #FFF;
  margin: 0.5em;
}
:host .product-name {
  display: block;
  text-align: center;
  text-decoration: none;
  color: #08C;
  border-top: 1px solid #EEE;
  font-weight: bold;
  padding: 0.75em 0;
}`;
  shadow.appendChild(styleEl);
};


var XProduct = document.registerElement('x-product', {
  prototype: XProductProto
});
body {
  background: #F7F7F7;
}

x-product {
  display: inline-block;
  float: left;
  margin: 0.5em;
  border-radius: 3px;
  background: #FFF;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  font-family: Helvetica, arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}
<x-product data-name="Ruby" data-img="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4621/ruby.png" data-url="http://example.com/1"></x-product>
<x-product data-name="JavaScript" data-img="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4621/javascript.png" data-url="http://example.com/2"></x-product>
<x-product data-name="Python" data-img="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4621/python.png" data-url="http://example.com/3"></x-product>

CSS Scoping Module Level 1 provides an answer to: Why is the shadow host so weird?:

The shadow host lives outside the shadow tree, and its markup is in control of the page author, not the component author.

It would not be very good if a component used a particular class name internally in a shadow tree stylesheet, and the page author using the component accidentally also used the the same class name and put it on the shadow host. Such a situation would result in accidental styling that is impossible for the component author to predict, and confusing for the page author to debug.

Related