diff --git a/packages/core/src/render3/features/external_styles_feature.ts b/packages/core/src/render3/features/external_styles_feature.ts index c31555780adf..0df3191e903a 100644 --- a/packages/core/src/render3/features/external_styles_feature.ts +++ b/packages/core/src/render3/features/external_styles_feature.ts @@ -25,10 +25,15 @@ export function ɵɵExternalStylesFeature(styleUrls: string[]): ComponentDefFeat } definition.getExternalStyles = (encapsulationId) => { - // Add encapsulation ID search parameter `component` to support external style encapsulation + // Add encapsulation ID search parameter `ngcomp` to support external style encapsulation as well as the encapsulation mode + // for usage tracking. const urls = styleUrls.map( (value) => - value + '?ngcomp' + (encapsulationId ? '=' + encodeURIComponent(encapsulationId) : ''), + value + + '?ngcomp' + + (encapsulationId ? '=' + encodeURIComponent(encapsulationId) : '') + + '&e=' + + definition.encapsulation, ); return urls; diff --git a/packages/platform-browser/src/dom/dom_renderer.ts b/packages/platform-browser/src/dom/dom_renderer.ts index 1bfc775ce6df..63891746c3f2 100644 --- a/packages/platform-browser/src/dom/dom_renderer.ts +++ b/packages/platform-browser/src/dom/dom_renderer.ts @@ -27,7 +27,7 @@ import { import {RuntimeErrorCode} from '../errors'; import {EventManager} from './events/event_manager'; -import {SharedStylesHost} from './shared_styles_host'; +import {createLinkElement, SharedStylesHost} from './shared_styles_host'; export const NAMESPACE_URIS: {[ns: string]: string} = { 'svg': 'http://www.w3.org/2000/svg', @@ -434,6 +434,23 @@ class ShadowDomRenderer extends DefaultDomRenderer2 { styleEl.textContent = style; this.shadowRoot.appendChild(styleEl); } + + // Apply any external component styles to the shadow root for the component's element. + // The ShadowDOM renderer uses an alternative execution path for component styles that + // does not use the SharedStylesHost that other encapsulation modes leverage. Much like + // the manual addition of embedded styles directly above, any external stylesheets + // must be manually added here to ensure ShadowDOM components are correctly styled. + // TODO: Consider reworking the DOM Renderers to consolidate style handling. + const styleUrls = component.getExternalStyles?.(); + if (styleUrls) { + for (const styleUrl of styleUrls) { + const linkEl = createLinkElement(styleUrl, doc); + if (nonce) { + linkEl.setAttribute('nonce', nonce); + } + this.shadowRoot.appendChild(linkEl); + } + } } private nodeOrShadowRoot(node: any): any { diff --git a/packages/platform-browser/src/dom/shared_styles_host.ts b/packages/platform-browser/src/dom/shared_styles_host.ts index ec6e40642684..b34ed4c0da4c 100644 --- a/packages/platform-browser/src/dom/shared_styles_host.ts +++ b/packages/platform-browser/src/dom/shared_styles_host.ts @@ -84,7 +84,7 @@ function addServerStyles( * @param doc A DOM Document to use to create the element. * @returns An HTMLLinkElement instance. */ -function createLinkElement(url: string, doc: Document): HTMLLinkElement { +export function createLinkElement(url: string, doc: Document): HTMLLinkElement { const linkElement = doc.createElement('link'); linkElement.setAttribute('rel', 'stylesheet'); linkElement.setAttribute('href', url);