How to style deep inside shadow trees - polymer

I have a problem with styling deep shadow trees. How can i apply some styles into shadow-dom ?
Here is i tried:
<link rel="import" href="../../bower_components/polymer/lib/elements/custom-style.html">
<custom-style>
<style is="custom-style">
vaadin-text-field [part='input-field']{
display: none;
}
</style>
</custom-style>
But its not working. Any advice ?

My understanding is that you can't, see:
https://www.polymer-project.org/2.0/docs/devguide/style-shadow-dom
"The HTML elements in your template become children in your custom element's shadow DOM. Shadow DOM provides a mechanism for encapsulation, meaning that elements inside the shadow DOM don't match selectors outside the shadow DOM."
Instead you need to extend the webcomponent, making custom version of it with your styles, the linked documentation gives information on that too.

you can use vaadin-themable-mixin to style parts elements.
But please note that once theme is loaded, it's will become global, so that all vaadin control in your website is styled by your theam.
read more at:
https://github.com/vaadin/vaadin-themable-mixin/wiki/1.-Style-Scopes

Related

Why can't I target my custom-defined HTML elements in CSS?

In my HTML, I've got:
<link rel="stylesheet" href="css/styles.css">
<script src="js/components/custom.js"></script>
...
<custom></custom>
In custom.js, say I've defined:
class Custom extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({mode: 'open'});
shadow.innerHTML = `
<style>
#import url('/css/styles.css');
</style>
...
`
}
}
customElements.define('custom', Custom)
In styles.css, when I define styles, they work. But I can't do something like
custom img {
}
to target an img inside custom. I have to use wrappers like div.custom-contents to target elements within.
Is this a known limitation perhaps with #imports like this, custom elements in general, or am I doing something wrong?
It is mandatory for custom elements that the name must consist of at least one letter, followed by a - dash, then at least one other letter. Your web component will not work if you don't conform to that requirement.
Your component uses shadow DOM. No outside styles affect the shadow DOM (other than inheritance), and no styles in the shadow DOM affect elements outside of of your component. This is the main concept behind shadow DOM - components bring their styling, and don't affect other elements on the page they're used in.
Also, you shouldn't attach the shadow DOM in the connectedCallback. That should always be done in the constructor.
You can use the part attribute along with the ::part pseudo element to allow styling from the outside.

Why does this globally defined css rule affect styling inside of the shadow DOM?

I created an web-component with shadow mode 'open', which is used like this:
<scu-switch checked="true" value="switch1">
<span id="scu-switch-label">Switch On</span>
</scu-switch>
and looks like this:
Than I added the button to a webpage with the following global CSS:
text-align: center;
and now the button style is broken:
When I inspect the button I can see, that the global style was applied to the span (and notice that it is not part of slot content) inside of the shadow root.
The shadow DOM is supposed to isolate style from the rest of the web page.
Why was this text-align: center applied here, even though it was defined outside of the Shadow DOM?
One of the great features of the Shadow DOM in Web Components is that styles are encapsulated to the component - you can style your component without worrying about any specifier (id, class, etc.) conflicts or styles 'leaking out' to other elements on the page.
This often leads to the belief that the reverse is true - that styles outside of the component won't cross the Shadow boundary and 'leak in' to your component. However this is only partly true.
While specifiers do not leak in to your component (e.g. a color applied to an p element in a style rule outside of your component won't effect any p elements in your Shadow DOM, although the rule will be applied to your Light DOM, or slotted content),
inheritable styles applied to any elements containing your component will be applied to both your Shadow and Light DOM.
Source: https://lamplightdev.com/blog/2019/03/26/why-is-my-web-component-inheriting-styles/

Shadow Dom and CSS3 :target selector

I should start off by saying that I don't really have an issue that I'm trying to work through. I just had an interesting thought about how Shadow Dom and the CSS3 :target selector might / should / currently do work together.
I know that HTML specification says that there should only ever be one element with a particular ID value in a valid HTML document. But when we start using webcomponents with shadow dom we could very easily find ourselves using multiple elements with the same ID. This is especially true when we use the same component multiple times in the same page. So the question that I have is this: what should happen to an element inside a shadow dom region that has an ID value which matches the current hash and which is styled with a :target rule?
For example, if I wrote a webcomponent (my-element) that contained
<style>
#debug {display:none}
#debug:target { display:block; background-color:yellow; border 2px solid red; }
</style>
<div id="debug">some debug data</div>
What should happen to all the instance of my-element that I put on a page and navigated to #debug on? Should the debug element in each component show? Should none of them show? Should only the first element's debug div show (the same one I'd expect the browser to try and navigate to)?
My opinion is that if the page does not have an element with an ID=debug value that no scrolling navigation should appear on the page. As shadow dom is isolated from the rest of the page's styles the browser shouldn't try to navigate to such an element nested in shadow dom. Each my-element instance should be able to see the current page's URL though and should apply any matching :target rules, such that each my-elements' debug div should be visible.
If this were the case it would make for some interesting possibilities for sharing page state across all components, such as the debug example above. However, I doubt that is how Chrome is currently implementing things. And I'm pretty sure this Shadow Dom polyfill isn't going to handle things correctly as it basically shoehorns everything into the page's Dom tree and that would break the html specification.
Just curious if anyone has an answer for how this should work and how it works today...
(edited from my pc to add formatting... hard to do from my phone)
I think you can see the shadow DOM like a nested document. CSS can't address elements inside the shadow DOM from the outside (previously existing shadow piercing CSS selectors were deprecated).
This also encapsulates ids and therefore multiple components that contain elements with an id won't cause collisions or duplicates.
If you have the CSS with the :target selector inside a components style, it should be able to address the element with the matching id, otherwise it shouldn't.
So the question that I have is this: what should happen to an element
inside a shadow dom region that has an ID value which matches the
current hash and which is styled with a :target rule?
Adding to Günter Zöchbauer above answer an alternative is to use the Custom Element object when the style is encapsulated, if the style is global it will work just fine. Use the define method to create a custom component as shown in the the docs. This will not encapsulate your elements so be aware that your styles can be shared across files.
So instead of doing this:
const shadow = this.attachShadow({ mode: "open" });
shadow.appendChild(pTag)
Use this:
this.appendChild(pTag);
both previous examples suppose you're in a HTMLElement class or a class that inherits it.

Cannot add ::after pseudo-element to slotted element in shadow dom

I was experimenting with Eric Bidelman's <fancy-tabs> shadow dom example: https://developers.google.com/web/fundamentals/getting-started/primers/shadowdom
And was trying to add Material Design styling to it, which would require adding an :after pseudo element to the tabs.
After some experimentation I found that the internal styles for applying pseudo elements do appear to work when using Polymer, but not when using vanilla JS...
Polymer example:
https://jsbin.com/maqaze/edit?html,output
Vanilla JS example:
In this second example, applying the :after pseudo element does not work within the shadow dom <style> it apparently needs to be set externally.
https://jsbin.com/toxalu/edit?html,output
So my question is, how should you go about adding a pseudo element to a slotted / light dom element, without needing to use external styles?
(have tried these examples on Chrome and Safari)
If it seems to work in Polymer it's due to the fact that Polymer 1.0 doesn't really use native ::slotted pseudo-elements.
In fact Polymer uses native Shadow DOM "v0" and converts ::slotted to ::content. You can see it in the Dev Tools.
As you have noted you can add ::after pseudo-elements from the outside.
I suppose pseudo-elements are considered as complex selectors and therefore are not supported within ::slotted().

Polymer and shadow DOM external styling

Hi I'm experimenting with Polymer and trying to style some polymer paper modules... In Polymer 1.0 they added this new properties in the CSS internal to shadow DOM's module... I am trying to change a color that is dependent on one of this properties --paper-input-container-focus-color for the paper-input-container module but I could not find any clear documentation or guide on how to actually access that property from...
I can style it overriding the CSS property via /deep/ or ::shadow but from my understanding this new method is supposed to avoid using those 2...
Can anyone point me in the right direction???
CLARIFICATION:
I am interested in the mixins Google introduced in polymer... that make use of #apply(--foo-bar)
As usual I answer my own question... But I really hope it can help others not wasting days like I do..
to take advantage of this new mixins to customize your shadow-element externally you need to add a style tag with the attribute is="custom-style" in your page before placing the custom-tag.
<style is="custom-style">
my-custom-module{
--my-custom-property-color: yellow;
}
</style>
<my-custom-module></my-custom-module>