Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Revert "feat(platform-browser): Add IsolatedShadowDom encapsulation m…
…ethod (#62723)"

This reverts commit d24d574. A
legitimate issue was raised in the original commit
(see d24d574#commitcomment-163853393)
  • Loading branch information
atscott committed Aug 13, 2025
commit 170ea6feb6f69e5f297e775db396d8073f38b728
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,7 @@
"enum": [
"Emulated",
"None",
"ShadowDom",
"IsolatedShadowDom"
"ShadowDom"
],
"description": "The view encapsulation strategy to use in the new application."
}
Expand Down Expand Up @@ -368,8 +367,7 @@
"enum": [
"Emulated",
"None",
"ShadowDom",
"IsolatedShadowDom"
"ShadowDom"
],
"description": "The view encapsulation strategy to use in the new component."
}
Expand Down
2 changes: 1 addition & 1 deletion adev/src/app/features/update/recommendations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1032,7 +1032,7 @@ export const RECOMMENDATIONS: Step[] = [
level: ApplicationComplexity.Advanced,
step: 'viewencapsulation native removed',
action:
'The component view encapsulation option `ViewEncapsulation.Native` has been removed. Use `ViewEncapsulation.ShadowDom` or `ViewEncapsulation.IsolatedShadowDom` instead. `ng update` will migrate you automatically.',
'The component view encapsulation option `ViewEncapsulation.Native` has been removed. Use `ViewEncapsulation.ShadowDom` instead. `ng update` will migrate you automatically.',
},
{
possibleIn: 1100,
Expand Down
2 changes: 1 addition & 1 deletion adev/src/content/ai/mcp-server-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,4 @@ This tool lists all the applications and libraries in your current Angular works

## Feedback and New Ideas

The Angular team welcomes your feedback on the existing MCP capabilities and any ideas you have for new tools or features. Please share your thoughts by opening an issue on the [angular/angular GitHub repository](https://github.com/angular/angular/issues).
The Angular team welcomes your feedback on the existing MCP capabilities and any ideas you have for new tools or features. Please share your thoughts by opening an issue on the [angular/angular GitHub repository](https://github.com/angular/angular/issues).
2 changes: 1 addition & 1 deletion adev/src/content/cli/help/generate.json
Original file line number Diff line number Diff line change
Expand Up @@ -998,4 +998,4 @@
"deprecated": false
}
]
}
}
2 changes: 1 addition & 1 deletion adev/src/content/cli/help/new.json
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,4 @@
"description": "Create an initial application that does not utilize `zone.js`."
}
]
}
}
6 changes: 3 additions & 3 deletions adev/src/content/guide/animations/complex-sequences.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,11 @@ IMPORTANT: If you need to animate the items of an `*ngFor` list and there is a p

## Animations and Component View Encapsulation

Angular animations are based on the components DOM structure and do not directly take [View Encapsulation](guide/components/styling#style-scoping) into account, this means that components using `ViewEncapsulation.Emulated` behave exactly as if they were using `ViewEncapsulation.None` (`ViewEncapsulation.ShadowDom` and `ViewEncapsulation.IsolatedShadowDom` behave differently as we'll discuss shortly).
Angular animations are based on the components DOM structure and do not directly take [View Encapsulation](guide/components/styling#style-scoping) into account, this means that components using `ViewEncapsulation.Emulated` behave exactly as if they were using `ViewEncapsulation.None` (`ViewEncapsulation.ShadowDom` behaves differently as we'll discuss shortly).

For example if the `query()` function (which you'll see more of in the rest of the Animations guide) were to be applied at the top of a tree of components using the emulated view encapsulation, such query would be able to identify (and thus animate) DOM elements on any depth of the tree.

On the other hand the `ViewEncapsulation.ShadowDom` and `ViewEncapsulation.IsolatedShadowDom` changes the component's DOM structure by "hiding" DOM elements inside [`ShadowRoot`](https://developer.mozilla.org/docs/Web/API/ShadowRoot) elements. Such DOM manipulations do prevent some of the animations implementation to work properly since it relies on simple DOM structures and doesn't take `ShadowRoot` elements into account. Therefore it is advised to avoid applying animations to views incorporating components using the ShadowDom view encapsulation.
On the other hand the `ViewEncapsulation.ShadowDom` changes the component's DOM structure by "hiding" DOM elements inside [`ShadowRoot`](https://developer.mozilla.org/docs/Web/API/ShadowRoot) elements. Such DOM manipulations do prevent some of the animations implementation to work properly since it relies on simple DOM structures and doesn't take `ShadowRoot` elements into account. Therefore it is advised to avoid applying animations to views incorporating components using the ShadowDom view encapsulation.

## Animation sequence summary

Expand All @@ -141,4 +141,4 @@ You might also be interested in the following:
<docs-pill href="guide/animations/transition-and-triggers" title="Transition and triggers"/>
<docs-pill href="guide/animations/reusable-animations" title="Reusable animations"/>
<docs-pill href="guide/routing/route-transition-animations" title="Route transition animations"/>
</docs-pill-row>
</docs-pill-row>
14 changes: 5 additions & 9 deletions adev/src/content/guide/components/styling.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ and [stylus](https://stylus-lang.com).
## Style scoping

Every component has a **view encapsulation** setting that determines how the framework scopes a
component's styles. There are four view encapsulation modes: `Emulated`, `ShadowDom`, `IsolatedShadowDom`, and `None`.
component's styles. There are three view encapsulation modes: `Emulated`, `ShadowDom`, and `None`.
You can specify the mode in the `@Component` decorator:

<docs-code language="angular-ts" highlight="[3]">
Expand Down Expand Up @@ -82,20 +82,16 @@ using [the web standard Shadow DOM API](https://developer.mozilla.org/docs/Web/W
When enabling this mode, Angular attaches a shadow root to the component's host element and renders
the component's template and styles into the corresponding shadow tree.

Styles inside the shadow tree cannot affect elements outside of that shadow tree.
This mode strictly guarantees that _only_ that component's styles apply to elements in the
component's template. Global styles cannot affect elements in a shadow tree and styles inside the
shadow tree cannot affect elements outside of that shadow tree.

Enabling `ShadowDom` encapsulation, however, impacts more than style scoping. Rendering the
component in a shadow tree affects event propagation, interaction
with [the `<slot>` API](https://developer.mozilla.org/docs/Web/Web_Components/Using_templates_and_slots),
and how browser developer tools show elements. Always understand the full implications of using
Shadow DOM in your application before enabling this option.

### ViewEncapsulation.IsolatedShadowDom

Behaves as above, except this mode strictly guarantees that _only_ that component's styles apply to elements in the
component's template. Global styles cannot affect elements in a shadow tree and styles inside the
shadow tree cannot affect elements outside of that shadow tree.

### ViewEncapsulation.None

This mode disables all style encapsulation for the component. Any styles associated with the
Expand All @@ -118,4 +114,4 @@ use [the `<link>` element](https://developer.mozilla.org/docs/Web/HTML/Element/l
reference CSS files. Additionally, your CSS may
use [the `@import`at-rule](https://developer.mozilla.org/docs/Web/CSS/@import) to reference
CSS files. Angular treats these references as _external_ styles. External styles are not affected by
emulated view encapsulation.
emulated view encapsulation.
2 changes: 1 addition & 1 deletion adev/src/content/reference/migrations/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ Learn about how you can migrate your existing angular project to the latest feat
<docs-card title="Self-closing tags" link="Migrate now" href="reference/migrations/self-closing-tags">
Convert component templates to use self-closing tags where possible.
</docs-card>
</docs-card-container>
</docs-card-container>
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class ComponentMetadataComponent {

private _nestedProps = inject(ElementPropertyResolver);

angularViewEncapsulationModes = ['Emulated', 'Native', 'None', 'ShadowDom', 'IsolatedShadowDom'];
angularViewEncapsulationModes = ['Emulated', 'Native', 'None', 'ShadowDom'];
acxViewEncapsulationModes = ['Emulated', 'None'];

readonly controller = computed(() => {
Expand Down
1 change: 0 additions & 1 deletion goldens/public-api/core/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2022,7 +2022,6 @@ export abstract class ViewContainerRef {
// @public
export enum ViewEncapsulation {
Emulated = 0,
IsolatedShadowDom = 4,
None = 2,
ShadowDom = 3
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -862,11 +862,7 @@ export class ComponentDecoratorHandler
}
}

if (
(encapsulation === ViewEncapsulation.ShadowDom ||
encapsulation === ViewEncapsulation.IsolatedShadowDom) &&
metadata.selector !== null
) {
if (encapsulation === ViewEncapsulation.ShadowDom && metadata.selector !== null) {
const selectorError = checkCustomElementSelectorForErrors(metadata.selector);
if (selectorError !== null) {
if (diagnostics === undefined) {
Expand Down
1 change: 0 additions & 1 deletion packages/compiler/src/compiler_facade_interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,6 @@ export enum ViewEncapsulation {
// Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
None = 2,
ShadowDom = 3,
IsolatedShadowDom = 4,
}

export type ChangeDetectionStrategy = number;
Expand Down
1 change: 0 additions & 1 deletion packages/compiler/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export enum ViewEncapsulation {
// Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
None = 2,
ShadowDom = 3,
IsolatedShadowDom = 4,
}

export enum ChangeDetectionStrategy {
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/compiler/compiler_facade_interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,6 @@ export enum ViewEncapsulation {
// Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
None = 2,
ShadowDom = 3,
IsolatedShadowDom = 4,
}

export type ChangeDetectionStrategy = number;
Expand Down
9 changes: 3 additions & 6 deletions packages/core/src/hydration/annotate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -792,12 +792,9 @@ function conditionallyAnnotateNodePath(
*/
function componentUsesShadowDomEncapsulation(lView: LView): boolean {
const instance = lView[CONTEXT];
if (!instance?.constructor) return false;
const def = getComponentDef(instance.constructor);
return (
def?.encapsulation === ViewEncapsulation.ShadowDom ||
def?.encapsulation === ViewEncapsulation.IsolatedShadowDom
);
return instance?.constructor
? getComponentDef(instance.constructor)?.encapsulation === ViewEncapsulation.ShadowDom
: false;
}

/**
Expand Down
6 changes: 0 additions & 6 deletions packages/core/src/metadata/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,4 @@ export enum ViewEncapsulation {
* all the Component's styling.
*/
ShadowDom = 3,
/**
* Similar to `ShadowDom`, but prevents any external styles from leaking into the
* component's ShadowRoot. This is useful when you want to ensure that the component's
* styles are completely isolated from the rest of the application, including global styles.
*/
IsolatedShadowDom = 4,
}
5 changes: 1 addition & 4 deletions packages/core/src/render3/hmr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,10 +245,7 @@ function recreateLView(
// shadow root. The browser will throw if we attempt to attach another one and there's no way
// to detach it. Our only option is to make a clone only of the root node, replace the node
// with the clone and use it for the newly-created LView.
if (
oldDef.encapsulation === ViewEncapsulation.ShadowDom ||
oldDef.encapsulation === ViewEncapsulation.IsolatedShadowDom
) {
if (oldDef.encapsulation === ViewEncapsulation.ShadowDom) {
const newHost = host.cloneNode(false) as HTMLElement;
host.replaceWith(newHost);
host = newHost;
Expand Down
5 changes: 1 addition & 4 deletions packages/core/src/render3/instructions/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,7 @@ export function locateHostElement(

// When using native Shadow DOM, do not clear host element to allow native slot
// projection.
const preserveContent =
preserveHostContent ||
encapsulation === ViewEncapsulation.ShadowDom ||
encapsulation === ViewEncapsulation.IsolatedShadowDom;
const preserveContent = preserveHostContent || encapsulation === ViewEncapsulation.ShadowDom;
const rootElement = renderer.selectRootElement(elementOrSelector, preserveContent);
applyRootElementTransform(rootElement as HTMLElement);
return rootElement;
Expand Down
34 changes: 4 additions & 30 deletions packages/platform-browser/src/dom/dom_renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,7 @@ export class DomRendererFactory2 implements RendererFactory2, OnDestroy {
if (
typeof ngServerMode !== 'undefined' &&
ngServerMode &&
(type.encapsulation === ViewEncapsulation.ShadowDom ||
type.encapsulation === ViewEncapsulation.IsolatedShadowDom)
type.encapsulation === ViewEncapsulation.ShadowDom
) {
// Domino does not support shadow DOM.
type = {...type, encapsulation: ViewEncapsulation.Emulated};
Expand Down Expand Up @@ -229,20 +228,7 @@ export class DomRendererFactory2 implements RendererFactory2, OnDestroy {
case ViewEncapsulation.ShadowDom:
return new ShadowDomRenderer(
eventManager,
element,
type,
doc,
ngZone,
this.nonce,
platformIsServer,
tracingService,
this.registry,
this.maxAnimationTimeout,
sharedStylesHost,
);
case ViewEncapsulation.IsolatedShadowDom:
return new ShadowDomRenderer(
eventManager,
element,
type,
doc,
Expand All @@ -253,7 +239,6 @@ export class DomRendererFactory2 implements RendererFactory2, OnDestroy {
this.registry,
this.maxAnimationTimeout,
);

default:
renderer = new NoneEncapsulationDomRenderer(
eventManager,
Expand Down Expand Up @@ -516,7 +501,6 @@ class DefaultDomRenderer2 implements Renderer2 {
}

const AT_CHARCODE = (() => '@'.charCodeAt(0))();

function checkNoSyntheticProp(name: string, nameKind: string) {
if (name.charCodeAt(0) === AT_CHARCODE) {
throw new RuntimeError(
Expand All @@ -537,6 +521,7 @@ class ShadowDomRenderer extends DefaultDomRenderer2 {

constructor(
eventManager: EventManager,
private sharedStylesHost: SharedStylesHost,
private hostEl: any,
component: RendererType2,
doc: Document,
Expand All @@ -546,7 +531,6 @@ class ShadowDomRenderer extends DefaultDomRenderer2 {
tracingService: TracingService<TracingSnapshot> | null,
registry: AnimationRemovalRegistry,
maxAnimationTimeout: number,
private sharedStylesHost?: SharedStylesHost,
) {
super(
eventManager,
Expand All @@ -558,12 +542,7 @@ class ShadowDomRenderer extends DefaultDomRenderer2 {
maxAnimationTimeout,
);
this.shadowRoot = (hostEl as any).attachShadow({mode: 'open'});

// SharedStylesHost is used to add styles to the shadow root by ShadowDom.
// This is optional as it is not used by IsolatedShadowDom.
if (this.sharedStylesHost) {
this.sharedStylesHost.addHost(this.shadowRoot);
}
this.sharedStylesHost.addHost(this.shadowRoot);
let styles = component.styles;
if (ngDevMode) {
// We only do this in development, as for production users should not add CSS sourcemaps to components.
Expand Down Expand Up @@ -609,23 +588,18 @@ class ShadowDomRenderer extends DefaultDomRenderer2 {
override appendChild(parent: any, newChild: any): void {
return super.appendChild(this.nodeOrShadowRoot(parent), newChild);
}

override insertBefore(parent: any, newChild: any, refChild: any): void {
return super.insertBefore(this.nodeOrShadowRoot(parent), newChild, refChild);
}

override removeChild(_parent: any, oldChild: any): void {
return super.removeChild(null, oldChild);
}

override parentNode(node: any): any {
return this.nodeOrShadowRoot(super.parentNode(this.nodeOrShadowRoot(node)));
}

override destroy() {
if (this.sharedStylesHost) {
this.sharedStylesHost.removeHost(this.shadowRoot);
}
this.sharedStylesHost.removeHost(this.shadowRoot);
}
}

Expand Down
Loading