AngularJSView Encapsulation

View Encapsulation

View Encapsulation is Angular's mechanism for scoping a component's CSS styles so they do not leak out and affect other components — and so external styles do not bleed in unexpectedly.

Without encapsulation, a CSS rule like p { color: red } in one component would affect every <p> tag in the entire application. Angular prevents this problem with three encapsulation modes.

The Three Encapsulation Modes

Mode

Value

How It Works

When to Use

Emulated (default)

ViewEncapsulation.Emulated

Angular adds unique attribute selectors to scope styles

Almost always — the safe default

None

ViewEncapsulation.None

Styles are global — no scoping at all

Global styles, style overrides

ShadowDom

ViewEncapsulation.ShadowDom

Native Shadow DOM — true style isolation

Custom elements, web component libraries

Emulated Encapsulation (Default)

ViewEncapsulation.Emulated is the default. Angular simulates Shadow DOM by automatically adding a unique attribute (like _ngcontent-abc-c123) to every element in the component's template and rewriting the CSS selectors to match only those attributes.

TS
// No encapsulation setting needed — Emulated is the default
@Component({
  selector: 'app-button',
  standalone: true,
  template: `<button class="btn">Click me</button>`,
  styles: [`
    .btn {
      background: #4caf50;
      color: white;
      padding: 0.5rem 1rem;
      border: none;
      border-radius: 4px;
    }
  `],
  // encapsulation: ViewEncapsulation.Emulated  ← this is the default
})
export class ButtonComponent {}

What Angular actually renders in the DOM:

HTML
<!-- Angular transforms your template to: -->
<app-button _nghost-abc-c123>
  <button class="btn" _ngcontent-abc-c123>Click me</button>
</app-button>

<!-- And rewrites your CSS to: -->
<style>
  .btn[_ngcontent-abc-c123] {
    background: #4caf50;
    color: white;
    padding: 0.5rem 1rem;
    border: none;
    border-radius: 4px;
  }
</style>

The scoped selector .btn[_ngcontent-abc-c123] means this style only matches the <button> inside ButtonComponent — not any other button in the app.

Note
The attribute names (_ngcontent-*, _nghost-*) are generated at compile time and will be consistent within a build, but may change between builds. Never rely on them in external CSS.
ViewEncapsulation.None

When encapsulation is set to None, Angular does not scope the component's styles at all. The styles are injected as global CSS that affects the entire page:

TS
import { Component, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'app-global-styles',
  standalone: true,
  template: `<div class="container"><ng-content /></div>`,
  styles: [`
    /* These styles are GLOBAL — they affect the entire app */
    * { box-sizing: border-box; }
    body { margin: 0; font-family: system-ui, sans-serif; }
    .container { max-width: 1200px; margin: 0 auto; padding: 0 1rem; }
  `],
  encapsulation: ViewEncapsulation.None,
})
export class GlobalStylesComponent {}
Warning
Using ViewEncapsulation.None makes your component's styles global. This can inadvertently affect other components. Only use it deliberately for theme-level or global utility styles.
Tip
ViewEncapsulation.None is useful for wrapper/theme components that intentionally need to style their descendants, or for components that need to style third-party content inside them.
ViewEncapsulation.ShadowDom

ShadowDom uses the browser's native Shadow DOM API for true encapsulation. The component gets a real Shadow DOM boundary — styles cannot cross it in either direction (by default):

TS
import { Component, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'app-isolated-widget',
  standalone: true,
  template: `
    <div class="widget">
      <h3>I am fully isolated</h3>
      <p>Global styles cannot affect me.</p>
    </div>
  `,
  styles: [`
    /* True Shadow DOM — these NEVER leak out */
    .widget {
      all: initial;  /* reset all inherited styles */
      font-family: 'Roboto', sans-serif;
      padding: 1rem;
      border: 2px solid #2196f3;
      border-radius: 8px;
    }
    h3 { color: #2196f3; margin: 0 0 0.5rem; }
    p { color: #333; margin: 0; }
  `],
  encapsulation: ViewEncapsulation.ShadowDom,
})
export class IsolatedWidgetComponent {}

Shadow DOM renders as:

HTML
<!-- In the DOM inspector, you see: -->
<app-isolated-widget>
  #shadow-root (open)
    <style>.widget { ... }</style>
    <div class="widget">
      <h3>I am fully isolated</h3>
      <p>Global styles cannot affect me.</p>
    </div>
</app-isolated-widget>
Styling Child Components from a Parent

A common question: "How do I style a child component's elements from the parent?"

With Emulated encapsulation (the default), parent styles cannot reach into a child component's view. Angular provides a few solutions:

TS
// Option 1: Use the :host pseudo-class to style the host element
@Component({
  selector: 'app-card',
  standalone: true,
  template: `<div class="card"><ng-content /></div>`,
  styles: [`
    :host {
      display: block;          /* make the host element a block */
      margin-bottom: 1rem;
    }
    :host(.featured) .card {   /* style when parent adds class="featured" */
      border: 2px solid gold;
    }
    :host-context(.dark-theme) .card {  /* style based on ancestor class */
      background: #333;
      color: white;
    }
  `],
})
export class CardComponent {}

TS
// Option 2: Use ::ng-deep (deprecated but still works)
// This pierces encapsulation and styles elements inside child components
@Component({
  selector: 'app-container',
  standalone: true,
  template: `<app-third-party-component />`,
  styles: [`
    /* Scope ::ng-deep with :host to avoid truly global styles */
    :host ::ng-deep .third-party-class {
      color: red !important;
    }
  `],
})
export class ContainerComponent {}
Warning
::ng-deep is deprecated. While it still works, avoid it for new code. Prefer passing styles via @Input() CSS custom properties (CSS variables), adding classes to the host via [class] binding, or using ViewEncapsulation.None on a parent wrapper component.
CSS Custom Properties — The Modern Approach

CSS custom properties (variables) cross the Shadow DOM boundary naturally. This makes them the best pattern for customizable component theming:

TS
// button.component.ts — uses CSS variables for theming
@Component({
  selector: 'app-button',
  standalone: true,
  template: `<button class="btn"><ng-content /></button>`,
  styles: [`
    .btn {
      background: var(--btn-bg, #4caf50);       /* fallback if not set */
      color: var(--btn-color, white);
      padding: var(--btn-padding, 0.5rem 1rem);
      border-radius: var(--btn-radius, 4px);
      border: none;
      cursor: pointer;
    }
  `],
})
export class ButtonComponent {}

HTML
<!-- Parent can customize via CSS variables — works even with ShadowDom! -->
<app-button style="--btn-bg: #e91e63; --btn-radius: 999px;">
  Rounded Pink Button
</app-button>

<!-- Or via a CSS class -->
<app-button class="danger-btn">Delete</app-button>

CSS
/* styles.css (global) */
.danger-btn {
  --btn-bg: #f44336;
  --btn-color: white;
}
The :host and :host-context Selectors

Angular provides special selectors for styling the component's host element from within:

CSS
/* :host — selects the component's host element (<app-card>) */
:host {
  display: block;
  border: 1px solid #eee;
  border-radius: 8px;
  overflow: hidden;
}

/* :host(selector) — styles the host only when it has the selector */
:host(.elevated) {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

/* :host-context(selector) — styles the host based on an ancestor */
:host-context(.dark-mode) {
  background: #1e1e1e;
  color: #fff;
  border-color: #444;
}
Global Styles vs Component Styles

Style Type

Location

Scope

Use For

Global styles

src/styles.css

Entire app

CSS resets, fonts, themes, utility classes

Component styles

@Component styles/styleUrl

This component only (Emulated/ShadowDom)

Component-specific UI

ViewEncapsulation.None

@Component with None

Entire app (leaked global)

Intentional global overrides

CSS custom properties

Anywhere

Inherited through DOM tree

Theming customizable components

TS
// Configure multiple style files per component
@Component({
  selector: 'app-data-table',
  standalone: true,
  styleUrls: [
    './data-table.component.css',      // main component styles
    './data-table.component.theme.css', // theme variations
  ],
  // OR (Angular 17+ single file shorthand)
  styleUrl: './data-table.component.css',
})
Practical Example — Building a Themed Button

TS
import { Component, Input } from '@angular/core';

type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'ghost';
type ButtonSize = 'sm' | 'md' | 'lg';

@Component({
  selector: 'app-btn',
  standalone: true,
  template: `
    <button
      [class]="classes"
      [disabled]="disabled"
    >
      <ng-content />
    </button>
  `,
  styles: [`
    :host { display: inline-block; }

    button {
      border: none;
      border-radius: 4px;
      cursor: pointer;
      font-weight: 500;
      transition: opacity 0.2s;
    }
    button:hover { opacity: 0.9; }
    button:disabled { opacity: 0.5; cursor: not-allowed; }

    .btn-sm { padding: 0.25rem 0.75rem; font-size: 0.875rem; }
    .btn-md { padding: 0.5rem 1rem; font-size: 1rem; }
    .btn-lg { padding: 0.75rem 1.5rem; font-size: 1.125rem; }

    .btn-primary { background: #2196f3; color: white; }
    .btn-secondary { background: #9e9e9e; color: white; }
    .btn-danger { background: #f44336; color: white; }
    .btn-ghost { background: transparent; color: #2196f3; border: 1px solid #2196f3; }
  `],
})
export class BtnComponent {
  @Input() variant: ButtonVariant = 'primary';
  @Input() size: ButtonSize = 'md';
  @Input() disabled = false;

  get classes(): string {
    return `btn-${this.size} btn-${this.variant}`;
  }
}

HTML
<!-- Using the themed button -->
<app-btn variant="primary" size="lg">Save Changes</app-btn>
<app-btn variant="danger">Delete Account</app-btn>
<app-btn variant="ghost" size="sm">Cancel</app-btn>
<app-btn [disabled]="isLoading">
  {{ isLoading ? 'Saving...' : 'Save' }}
</app-btn>
Summary
  • Emulated (default): Angular adds attribute selectors to scope styles — no native browser support needed

  • None: styles are global — useful for intentional cross-component styling

  • ShadowDom: uses native Shadow DOM for true isolation — best for web components / design systems

  • Use :host to style the component host element from within the component styles

  • Use CSS custom properties (variables) as a clean API for parent-controlled theming

  • Avoid ::ng-deep — prefer CSS variables or explicit @Input for style customization

  • Put global resets, fonts, and theme tokens in src/styles.css