Skip to content

Commit c36a1c0

Browse files
clydinpkozlowski-opensource
authored andcommitted
fix(platform-browser): correctly add external stylesheets to ShadowDOM components (#58482)
Angular components that use ShadowDOM view encapsulation have an alternate execution path for adding component styles to the DOM that does not use the SharedStylesHost that all other view encapsulation modes leverage. To ensure that ShadowDOM components receive all defined styles, additional logic has been added to the ShadowDOM specific renderer to also cover external styles. PR Close #58482
1 parent 90509f8 commit c36a1c0

File tree

3 files changed

+26
-4
lines changed

3 files changed

+26
-4
lines changed

packages/core/src/render3/features/external_styles_feature.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,15 @@ export function ɵɵExternalStylesFeature(styleUrls: string[]): ComponentDefFeat
2525
}
2626

2727
definition.getExternalStyles = (encapsulationId) => {
28-
// Add encapsulation ID search parameter `component` to support external style encapsulation
28+
// Add encapsulation ID search parameter `ngcomp` to support external style encapsulation as well as the encapsulation mode
29+
// for usage tracking.
2930
const urls = styleUrls.map(
3031
(value) =>
31-
value + '?ngcomp' + (encapsulationId ? '=' + encodeURIComponent(encapsulationId) : ''),
32+
value +
33+
'?ngcomp' +
34+
(encapsulationId ? '=' + encodeURIComponent(encapsulationId) : '') +
35+
'&e=' +
36+
definition.encapsulation,
3237
);
3338

3439
return urls;

packages/platform-browser/src/dom/dom_renderer.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
import {RuntimeErrorCode} from '../errors';
2828

2929
import {EventManager} from './events/event_manager';
30-
import {SharedStylesHost} from './shared_styles_host';
30+
import {createLinkElement, SharedStylesHost} from './shared_styles_host';
3131

3232
export const NAMESPACE_URIS: {[ns: string]: string} = {
3333
'svg': 'http://www.w3.org/2000/svg',
@@ -434,6 +434,23 @@ class ShadowDomRenderer extends DefaultDomRenderer2 {
434434
styleEl.textContent = style;
435435
this.shadowRoot.appendChild(styleEl);
436436
}
437+
438+
// Apply any external component styles to the shadow root for the component's element.
439+
// The ShadowDOM renderer uses an alternative execution path for component styles that
440+
// does not use the SharedStylesHost that other encapsulation modes leverage. Much like
441+
// the manual addition of embedded styles directly above, any external stylesheets
442+
// must be manually added here to ensure ShadowDOM components are correctly styled.
443+
// TODO: Consider reworking the DOM Renderers to consolidate style handling.
444+
const styleUrls = component.getExternalStyles?.();
445+
if (styleUrls) {
446+
for (const styleUrl of styleUrls) {
447+
const linkEl = createLinkElement(styleUrl, doc);
448+
if (nonce) {
449+
linkEl.setAttribute('nonce', nonce);
450+
}
451+
this.shadowRoot.appendChild(linkEl);
452+
}
453+
}
437454
}
438455

439456
private nodeOrShadowRoot(node: any): any {

packages/platform-browser/src/dom/shared_styles_host.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ function addServerStyles(
8484
* @param doc A DOM Document to use to create the element.
8585
* @returns An HTMLLinkElement instance.
8686
*/
87-
function createLinkElement(url: string, doc: Document): HTMLLinkElement {
87+
export function createLinkElement(url: string, doc: Document): HTMLLinkElement {
8888
const linkElement = doc.createElement('link');
8989
linkElement.setAttribute('rel', 'stylesheet');
9090
linkElement.setAttribute('href', url);

0 commit comments

Comments
 (0)