skip to content

View Encapsulation Modes

ViewEncapsulation Emulated, ShadowDom and None, with :host, :host-context() and the discouraged ::ng-deep. Interviewers ask how emulated scoping works and where component styles leak.

part ofAngularoverview, primer and where to startread it →
on this pageshow

explore

questions

5

What view encapsulation modes can an Angular component use, which one is the default, and how do they differ?

level: juniorimportance: must knowfreq 64%

answer

  1. four enum members, one experimental
  2. attributes versus a real shadow root
  3. None means global
  4. global styles reach in, or not

basics

~10 s

ViewEncapsulation offers Emulated (the default: compiler-added attributes scope the styles), ShadowDom (a real shadow root), ExperimentalIsolatedShadowDom (a shadow root that also keeps shared styles out) and None (the styles act globally).

solid answer

~40 s

The `encapsulation` field of `@Component` takes a `ViewEncapsulation` value. **`Emulated`** is the default: the compiler rewrites each selector with a component-specific attribute and the renderer stamps that attribute on the template's elements, so styles don't leak out, while global styles still reach in. **`ShadowDom`** attaches an open shadow root to the host and renders the template and styles inside it, so document styles cannot match inside; Angular still copies the other components' registered styles into each shadow root, and the mode also changes event retargeting, `<slot>` behaviour and dev-tools inspection. **`ExperimentalIsolatedShadowDom`** (experimental since v21) leaves those shared styles out as well. **`None`** turns scoping off: the component's styles are added to the document and match anywhere while the component is in use.

code

ts · 12 lines
ts
import { Component, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'app-support-widget',
  encapsulation: ViewEncapsulation.ShadowDom,
  template: `<button type="button">Chat with support</button>`,
  styles: `
    :host { display: block; }
    button { border-radius: 8px; }
  `,
})
export class SupportWidget {}

go deeper

for a junior

Recall the mode names, that Emulated is the default, that ShadowDom uses a real shadow root, and that None makes a component's styles global.

for a middle

Explain how Emulated scopes with attributes, why global styles still reach in, and what ShadowDom changes beyond CSS, including the shared styles Angular copies into shadow roots.

for a senior

Justify a mode per situation: Emulated by default, ShadowDom for widgets on foreign pages, None only with prefixed selectors, and the isolated variant's experimental status.

for a principal

Frame encapsulation as a design-system policy: which modes a library allows, how theming crosses boundaries, and what embedding in non-Angular pages demands.

## Where the setting lives Every Angular component has a **view encapsulation** mode that decides how far its styles (from `styles`, `styleUrl`, or a `<style>` element in its template) can reach. You set it with the `encapsulation` field of `@Component`, using the `ViewEncapsulation` enum from `@angular/core`. If you set nothing, the component uses `Emulated`. ## The four modes at a glance | Mode | Mechanism | Styles leak out? | Outside styles reach in? | |---|---|---|---| | `Emulated` (default) | compile-time selector rewrite plus attributes | no | yes, global styles apply | | `ShadowDom` | native open shadow root on the host | no | document stylesheets no; Angular's shared component styles are copied in | | `ExperimentalIsolatedShadowDom` | native shadow root, no shared styles | no | no, only the component's own styles | | `None` | no scoping at all | yes, rules are global | yes | The enum value `1` is missing on purpose: it was the old `Native` mode, removed in v11. ## Emulated: scoping without Shadow DOM The compiler appends an attribute selector such as `[_ngcontent-ng-c1234]` to each compound selector in the component's CSS, and turns `:host` into `[_nghost-ng-c1234]`. At runtime the renderer adds the matching attribute to every element the component's template creates, and the host attribute to the host element. Because the rules now require that attribute, they cannot match anything outside the component. Global styles are untouched, so they still apply inside. A component with no styles at all is quietly compiled as `None`, since there is nothing to scope. ## ShadowDom: real isolation, real side effects With `ShadowDom` Angular calls `attachShadow({ mode: 'open' })` on the host and renders the template and the component's styles into that shadow tree. Consequences worth naming in an interview: - **Document stylesheets stop matching inside.** A global rule for `button` no longer styles the component's buttons; only inherited properties and custom properties cross the boundary. - **Angular's shared styles are copied in.** Styles of the application's `Emulated` and `None` components are added to each shadow root, so a `None` component's global-looking rules still apply there. `ExperimentalIsolatedShadowDom` exists precisely to leave these out, so that only the component's own styles apply. - **More than CSS changes.** Events are retargeted at the shadow boundary, native `<slot>` semantics come into play, and the browser's dev tools show a shadow tree. The docs tell you to understand these implications before enabling the mode. - **Selectors are evaluated natively.** `:host` and `:host-context()` are left to the browser rather than rewritten, so browser support rules apply. ## None: global by choice `ViewEncapsulation.None` skips all rewriting. The component's rules are added to the document when the component renders and behave like any global stylesheet, matching elements anywhere, including inside other components. That is occasionally useful for a deliberately global theme component, but every selector must be written defensively (prefixed with a class the component owns), and the styles are removed again once no instance remains, which surprises code that relied on them. ## Common misconceptions - **"Emulated uses Shadow DOM."** It uses no shadow root at all; the scoping is pure compile-time rewriting plus attributes. - **"Encapsulation blocks global CSS."** `Emulated` lets global rules in freely; `ShadowDom` keeps document stylesheets out but still receives Angular's shared component styles; only `ExperimentalIsolatedShadowDom` keeps both out. - **"None is just Emulated without the attribute noise."** Removing the attributes removes the scoping: every rule becomes page-wide. - **"ShadowDom is a drop-in upgrade."** It changes event retargeting, projection semantics and how tests query the DOM, so switching an existing component is a behaviour change. ## Choosing a mode 1. Keep **`Emulated`** for almost everything; it is the default for good reasons and works everywhere. 2. Reach for **`ShadowDom`** when you need true isolation from document styles, for example a widget embedded in pages you do not control, and accept the event, slot and tooling differences. 3. Consider **`ExperimentalIsolatedShadowDom`** only when even Angular's shared styles must stay out, remembering it is experimental. 4. Use **`None`** sparingly, with prefixed selectors, and document why the component's styles are global. A related rule of thumb: the mode is a property of the component that declares the styles. A parent's mode never changes how a child's styles are scoped, and switching a parent to `None` does not let a child's styles out.

  • Does a component using ViewEncapsulation.ShadowDom see the application's global stylesheet?
    Not through selectors: a stylesheet linked in the document does not match elements inside a shadow root; only inherited properties and custom properties cross. Angular does copy its registered component styles, from Emulated and None components, into each shadow root, which is what `ExperimentalIsolatedShadowDom` leaves out.
  • Why does a component with Emulated encapsulation but no styles show no _ngcontent attributes?
    When a component declares no styles, the compiler switches its encapsulation from `Emulated` to `None`, because there is nothing to scope. Its elements are then created without scoping attributes, which keeps the DOM leaner.

saying these in an interview costs you the question

  • ShadowDom is Angular's default encapsulation mode.
  • Emulated encapsulation also stops global styles from affecting the component.
  • ViewEncapsulation.None still scopes styles, it just skips the attribute rewrite.
  • Switching to ShadowDom changes only CSS, nothing about events or projection.
  • Emulated mode relies on the browser's native Shadow DOM under the hood.
open as a page

How does Angular's default Emulated view encapsulation scope a component's CSS, and where does that scoping stop?

level: middleimportance: must knowfreq 58%

basics

~20 s

At compile time Angular appends a component-specific attribute selector to every rule; at runtime it stamps _ngcontent on elements the template creates and _nghost on the host. Styles cannot leak out, but global styles still apply inside.

open as a page

In an Angular component's styles, what do :host and :host-context() select, and how does Emulated mode compile them?

level: middleimportance: should knowfreq 44%

basics

~20 s

:host targets the component's host element, with :host(.x) adding a condition on it; :host-context(.x) applies when the host or any ancestor matches. In Emulated mode the compiler rewrites both into selectors on the _nghost attribute.

open as a page

Why can't an Angular wrapper component's Emulated styles restyle the internals of a third-party date picker it contains, and what are the options and their leakage risks?

level: seniorimportance: should knowfreq 50%

basics

~20 s

The picker's cells are created by its own template or code, so they lack the wrapper's _ngcontent attribute. Prefer the library's theming API; otherwise a class-scoped global rule, or :host ::ng-deep as a discouraged, host-bounded last resort.

open as a page

In an Angular 22 app, part of a page loses its styling after a ViewEncapsulation.None component is destroyed; what explains it, and how do you fix it?

level: seniorimportance: nice to knowfreq 18%

basics

~20 s

Angular removes a component's styles from the DOM once no instance using them remains, and v22 extended removal to styles whose host is dropped. Rules a None component carried for other DOM vanish with it; move them to a global stylesheet.

open as a page