Styles from external components are included outside the scope of a shadow DOM component
See original GitHub issue🐞 bug report
Affected Package
The issue is caused by package @angular/platform-browser
Is this a regression?
No
Description
When deploying an Angular component with encapsulation: ViewEncapsulation.ShadowDom
, everything regarding the component should be kept inside the #shadow-root
. This includes all stylings.
Actual behavior
- Styles added by
styleUrls
orstyles
in the@Component
decorator are added to the#shadow-root
✔️ - Styles coming from external components like @angular/material are added to the
#shadow-root
✔️ - Styles coming from external components are also added to document’s
<head>
outside of the#shadow-root
❌
Expected behavior
Only 1. and 2. should happen.
Root cause analysis
As far as I can see, this is caused by the ShadowDomRenderer
using the DomSharedStylesHost
which adds _doc.head
to its list of known _hostNodes
in the constructor:
https://github.com/angular/angular/blob/d43187f7ef7e841d84ecf594e8e515a9d534daaa/packages/platform-browser/src/dom/shared_styles_host.ts#L39
🔬 Minimal Reproduction
https://stackblitz.com/edit/angular-material-shadowdom-styles
In the <head>
section there are <style>
tags of Material components, which should only be inside the shadow DOM.
🌍 Your Environment
Angular Version:
Angular CLI: 8.3.23
Node: 12.7.0
OS: win32 x64
Angular: 8.2.14
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Package Version
-----------------------------------------------------------
@angular-devkit/architect 0.803.23
@angular-devkit/build-angular 0.803.23
@angular-devkit/build-optimizer 0.803.23
@angular-devkit/build-webpack 0.803.23
@angular-devkit/core 8.3.23
@angular-devkit/schematics 8.3.23
@angular/cdk 8.2.3
@angular/cli 8.3.23
@angular/material 8.2.3
@ngtools/webpack 8.3.23
@schematics/angular 8.3.23
@schematics/update 0.803.23
rxjs 6.4.0
typescript 3.5.3
webpack 4.39.2
Issue Analytics
- State:
- Created 4 years ago
- Reactions:4
- Comments:5
@Megadesty
We have encountered the same issue. One way we’ve worked around it is that we have a project dedicated to creating web components. In the bootstrapped module where we declare our custom elements, we do the following in the constructor of the NgModule:
@alexeykostevich Your extended example is excellent and showcases the (faulty) behavior with components
ViewEncapsulation.Emulated
inside a#shadow-root
as well, thanks!I think if you are happy with the surrogate ids, that’s fine. But as you can see in my and your example, the common Material styles (like
.mat-card {...}
) are also included in both the document and#shadow-root
. Now think about having mulitple Web Components on one page, all are self-contained Angular apps using Material. What you get in the end is that each component injects its own Material style in the document and since they are always named the same, they are overwriting each other. This could lead to trouble if one Web Component uses an older Angular or Material version or another Material theme. And even if all Web Components are using the same Material version and the same theme, in my opinion this is not good at all.In our case we already have multiple Web Components using Angular with Material on a page. The document’s
<head>
looks like this:If the Angular team fixes this issue, I guess it won’t have an impact on your project. Except you are using global styles from a Web Component outside the component, but that sounds like a bad practice anyway.