docs: clarify support for ViewEncapsulation.ShadowDom
Proposal
What is the expected behavior?
If ViewEncapsulation.ShadowDom is not supported, this should be called out in the docs to save developers time and frustration.
What is the current behavior?
ViewEncapsulation.ShadowDom is not supported and is not documented.
What are the steps to reproduce?
- Open https://stackblitz.com/edit/angular-i5jw3k?file=app/table-selection-example.ts
- Notice how the checkboxes aren't themed
- Open https://stackblitz.com/edit/angular-sbrzfb?file=app/input-overview-example.ts
- Notice how the inputs are not themed or styled properly
What is the use-case or motivation for changing an existing behavior?
To save developers time and frustration.
Which versions of Angular, Material, OS, TypeScript, browsers are affected?
Angular: 7.0.0 Angular Material: 7.0.2 TypeScript: ~3.1.1 Browsers: Tested on Chrome, Firefox, and Safari latest stable versions
Is there anything else we should know?
Nope
Is there any plans to support ShadowDom at some point?
We have to define that "support" means, as well. We'll probably never change the components to use Shadow DOM, but when we switch to CSS variables the theming system won't prevent other people from using it.
@jelbourn where is this on the road map (days, weeks, months)? We're starting to plow headlong into a webcomponent architecture but are heavily invested (and wish to remain so) with our material components.
Are you aware of a way to work around this. Since we're just starting off with componentizing some of our resources, it wouldn't be much effort to make the components happy with angular.
Switching the theming system to use CSS variables is probably going to be early 2020, but for other things (like overlays) we don't have concrete plans yet.
Note that when working with Angular Elements, ViewEncapsulation.None and using Sass (SCSS) to make sure that your styles are scoped to components is recommended at this time.
We are now approaching mid 2020. What is the status and roadmap of this?
Being able to use material in components with ShadowDom opens a lot of opportunities and cleaner components/code/CSS.
Hi folks, just bumping this issue again. Is there a recommended way to use ShadowDom without losing all the styling on Material components?
Angular is dropping IE11 support in v13, which opens the door to us switching to CSS variables, which would make it possible to support Shadow DOM.
Sometime in the next year we do plan on revamping our theming system. This would involve switching to CSS variables and aligning more closely with the current Material Design spec, and would probably coincide with moving the MDC-based components to stable. However, we don't yet have the detailed design of what that would look like.
As MDC based components are beeing used for Material since Angular 15, i want to just bump this issue. Does this have any meaning to Material/ShadowDom?
We are now approaching mid 2020. What is the status and roadmap of this?
Being able to use material in components with ShadowDom opens a lot of opportunities and cleaner components/code/CSS.
We are now in 2024 and as far as I can tell Angular Material is still not supported with encapsulation ShadowDOM. I was following the statement that css has to be loaded inside the shadow root but without any impact. Component was still not rendered correctly.
Is there any chance to get some perspective on this? For our enterprise applications it is really causing issues and we are considering migrating away from angular material!
It is starting to feel like this might never come?
Hello,
It would be nice to have this support for our web components. ..Bump..
Bump ! Waiting for Shadow DOM support.
It kind of seems to me like two major Angular features (Angular Material and Angular Elements) do not work correctly together. At least assuming ShadowDom encapsulation is used -- and it really seems like most people would want that on their generated web components, unless I'm missing something.
Anyway, we just finished converting to the MDC Material components, and this issue is actually worse now.
Background: We take a component from our app and use a second project/build to "export" it as a web component (via Angular Elements) so that other sites can use it. This uses ShadowDom encapsulation because obviously we want it isolated when running elsewhere. We take the app's main styles.scss (where Material is imported) and pull it into the exported component directly. This causes all the main styles, including Material stuff, to be present in a <style> node inside the #shadow-root.
This was working, but now with MDC it seems like a lot of the styling is defined via global CSS variables in rules like this:
html {
--mat-divider-color: rgba(0, 0, 0, 0.12);
--mat-expansion-container-background-color: white;
--mat-expansion-container-text-color: rgba(0, 0, 0, 0.87);
--mat-expansion-actions-divider-color: rgba(0, 0, 0, 0.12);
--mat-expansion-header-hover-state-layer-color: rgba(0, 0, 0, 0.04);
--mat-expansion-header-focus-state-layer-color: rgba(0, 0, 0, 0.04);
--mat-expansion-header-disabled-state-text-color: rgba(0, 0, 0, 0.26);
--mat-expansion-header-text-color: rgba(0, 0, 0, 0.87);
--mat-expansion-header-description-color: rgba(0, 0, 0, 0.54);
--mat-expansion-header-indicator-color: rgba(0, 0, 0, 0.54);
--mat-expansion-header-collapsed-state-height: 48px;
--mat-expansion-header-expanded-state-height: 64px;
--mat-icon-color: inherit;
}
These styles are not accessible by the component in the shadow DOM, resulting in broken style on all the Material controls. If we could just change the html selector to :host, it would work perfectly for our case.
Getting desperate to find any workaround besides creating our own separate, hardcoded copy of those CSS variables...
Edit: as @MirkoAdolph pointed out, the Angular docs say:
Angular Material assumes that, by default, all theme styles are loaded as global CSS. If you want to use Shadow DOM in your application, you must load the theme styles within each shadow root that contains an Angular Material component. You can accomplish this by manually loading the CSS in each shadow root, or by using Constructable Stylesheets.
It appears loading the theme styles within each shadow root no longer works. I'll admit I don't understand Constructable Stylesheets well enough to know if that is an option for SCSS provided by Angular Material that we don't control.
Now with MDC it seems like a lot of the styling is defined via global CSS variables ... These styles are not accessible by the component in the shadow DOM, resulting in broken style on all the Material controls.
If anyone is stuck on the same problem, we addressed it with an ugly hack that modifies the style nodes at runtime:
//Find all <style> elements inside the current component's shadow root
let styleElements = this.elementRef.nativeElement.shadowRoot.querySelectorAll('style');
//Replace relevant instances of "html{" or ":root{" with ":host{"
styleElements.forEach((styleElement: Element) => {
if (styleElement.textContent) {
styleElement.textContent = styleElement.textContent.replace(/html{--mat/g, ':host{--mat'); //e.g. "html{--mat-divider-color: rgba(0, 0, 0, 0.12); ..."
styleElement.textContent = styleElement.textContent.replace(/html{--mdc/g, ':host{--mdc'); //e.g. "html{--mdc-filled-text-field-caret-color: #25c9d0; ..."
styleElement.textContent = styleElement.textContent.replace(/html .mat-/g, ':host .mat-'); //e.g. "html .mat-mdc-form-field.mat-accent { ..."
styleElement.textContent = styleElement.textContent.replace(/:root{--mat/g, ':host{--mat'); //e.g. ":root{--mat-select-panel-background-color: white; ..."
styleElement.textContent = styleElement.textContent.replace(/:root{--mdc/g, ':host{--mdc'); //e.g. ":root{--mdc-filled-text-field-caret-color: #25c9d0; ..."
styleElement.textContent = styleElement.textContent.replace(/:root .mat-/g, ':host .mat-'); //e.g. ":root .mat-mdc-form-field.mat-accent { ..."
}
});