Objective
In my Angular 11 website, there is a comprehensive form component created using Angular Material named myExportableComponent
. I aim to utilize this component in the site as usual, but also export it as a generic web component or "custom element," known as an "Angular Element." This will enable its usage on any third-party platform, regardless of their technology stack, while functioning identically to how it operates on my site.
myExportableComponent
should retain normal functionality as an Angular component within my website. It should be customizable through both global CSS located in styles.scss
and component-specific CSS found in my-exportable.component.scss
.
When implemented as a web component, myExportableComponent
must also respond to global and component-specific CSS styling like regular, without impacting the surrounding elements on the third-party page where it is embedded. This aspect presents a challenge for me.
Current Configuration
The myExportableComponent
is organized within a distinct sub-project of the main project. I am able to build it independently and integrate the generated js/css files into another site successfully. The process resembles:
<link rel="stylesheet" href="myExportableComponentStyles.css">
<script type="text/javascript" src="myExportableComponent.js"></script>
<div class="mat-app-background mat-typography">
<my-exportable-component></my-exportable-component>
</div>
To ensure that myExportableComponent
shares styles with my primary site, adjustments were made in angular.json
, linking it to the main app's theme.scss
file (containing Angular material theme) and styles.scss
(additional global styles). The setup looks like this...
angular.json:
"mainApp": {
...
"styles": [
"src/theme.scss",
"src/styles.scss"
],
"myExportableComponentApp": {
...
"styles": [
"src/theme.scss", //NOT "projects/myExportableComponentApp/src/theme.scss"
"src/styles.scss" //NOT "projects/myExportableComponentApp/src/styles.scss"
],
Issue at Hand
The global CSS does not remain contained when the web component is inserted on a different site. For instance, adding a global link style for my app in styles.scss
impacts all links on the external site's layout too. While the styles from theme.scss
(Material) appear isolated, this may change if the host site also employs Angular Material.
Potential Solutions
Idea #1: encapsulation settings
Considering employing
encapsulation: ViewEncapsulation.ShadowDom
on myExportableComponent
, however, A) it disrupts some of the Material styling and icons, and B) it fails to address the fundamental issue concerning global CSS. Furthermore, the default setting appears effective in containing component-specific CSS.
Idea #2: target global CSS to my HTML only
If consumers could include a specific class in their HTML tag as present in my app and apply it around the web component, it might allow targeting of global CSS solely to elements within those containers, such as:
.special-wrapper a {
/* styling */
}
This method does isolate global styles from the third-party page effectively. Nonetheless, it seems to result in a precedence conflict where global styles override component-specific styles erroneously.
Idea #3: utilization of :host or :host-context selectors in global CSS?
I confess struggling with implementing these selectors and observed no noticeable impact in my application.
Idea #4: Build-time scripts?
Upon building the myExportableComponent
sub-project, if there exists a means to automatically extract all global CSS from theme.scss
and
styles.scss</code, transferring them to the beginning of <code>my-exportable.component.scss</code, it could potentially resolve the issue. Consequently, my "global" styles would then remain encapsulated within the web component due to placement in the component-specific file.</p>
<p>Is such a modification feasible during the execution of <code>ng build myExportableComponentApp --prod
? Regrettably, I lack initial guidance on the implementation.
Any innovative suggestions are welcome!