Components

This section documents modern, standalone Angular — signals, the built-in @if / @for / @switch control flow, @defer, typed reactive forms, provideHttpClient, functional guards and interceptors, and server-side rendering with hydration — as described by the official documentation at angular.dev, which is the reference these pages are written and verified against.

This content was generated with the assistance of AI and should be verified against angular.dev before being relied on in production. Angular ships a major release roughly every six months and its APIs continue to evolve: the examples here target the current major release; where a consulted source disagrees with the current documentation, the documentation wins and the difference is noted.

This section’s bibliography lists the reference material consulted while preparing these pages.

A component is a TypeScript class with an @Component decorator that pairs a template with the logic and state that drive it. Components are the only building block you need to compose an Angular UI; every screen is a tree of them.

@Component metadata

The decorator’s configuration object describes how Angular compiles and renders the class. The common fields:

  • selector — the CSS selector that marks where this component mounts in a template.

  • template (inline) or templateUrl (a separate .html file).

  • styles (inline) or styleUrl / styleUrls (separate stylesheet files).

  • standalone — defaults to true; a standalone component manages its own dependencies and does not belong to an NgModule.

  • imports — the other components, directives, and pipes this template uses.

  • host — bindings and listeners applied to the component’s own host element.

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

@Component({
  selector: 'app-counter',
  imports: [],
  template: `
    <p>Count: {{ count() }}</p>
    <button (click)="increment()">+1</button>
  `,
  styles: `
    :host { display: inline-flex; gap: .5rem; }
    button { font: inherit; }
  `,
})
export class Counter {
  readonly count = signal(0);

  increment(): void {
    this.count.update((n) => n + 1);
  }
}

See Components for the full metadata reference.

The component class and the render tree

Angular instantiates one object of the component class per place the selector appears. That instance owns the template’s state; the template reads it through bindings and calls its methods from event handlers. Nesting components — by putting one component’s selector in another’s template — builds a render tree rooted at the component passed to bootstrapApplication.

flowchart TD App --> Header App --> ProductList ProductList --> ProductCard1["ProductCard"] ProductList --> ProductCard2["ProductCard"] ProductList --> ProductCard3["ProductCard"]

Selectors come in three forms:

@Component({ selector: 'app-card', /* ... */ })          // element:   <app-card>
@Component({ selector: '[appHighlight]', /* ... */ })     // attribute: <div appHighlight>
@Component({ selector: '.app-toolbar', /* ... */ })       // class:     <div class="app-toolbar">

Element selectors are the norm for components; attribute selectors are typical for directives. See component selectors.

Styling and view encapsulation

Styles declared in styles / styleUrl are scoped to the component by default. Angular’s ViewEncapsulation setting controls how:

  • Emulated (default) — Angular rewrites selectors and adds per-component attributes so the styles do not leak out or in. No native Shadow DOM.

  • None — styles are added to the document <head> as-is and apply globally.

  • ShadowDom — the component renders into a real shadow root; browser-native style isolation.

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

@Component({
  selector: 'app-badge',
  template: `<span class="dot"></span><ng-content />`,
  styleUrl: './badge.scss',
  encapsulation: ViewEncapsulation.Emulated,
})
export class Badge {}
:host {
  display: inline-block;
}

:host(.danger) .dot {          // host element that also has the .danger class
  background: red;
}

:host-context(.dark-theme) {   // an ancestor anywhere has .dark-theme
  color: #eee;
}

::ng-deep .legacy-child {       // deprecated: pierces into child components
  margin: 0;
}

:host targets the component’s own element, :host-context() styles it based on an ancestor, and ::ng-deep forces a style through to descendants — it is deprecated; prefer exposing a CSS custom property or moving the rule to src/styles.css, the global stylesheet listed in angular.json. See styling components.

Host elements

Every component instance has a host element — the DOM element its selector matched. Bind to it and listen on it through host metadata, and compose behaviour onto it with hostDirectives:

import { Component } from '@angular/core';
import { Tooltip } from './tooltip';

@Component({
  selector: 'app-icon-button',
  template: `<ng-content />`,
  host: {
    'role': 'button',
    'tabindex': '0',
    '[class.is-active]': 'active()',
    '(keydown.enter)': 'activate()',
  },
  hostDirectives: [Tooltip],
})
export class IconButton {
  // active(), activate() defined here
}

hostDirectives applies Tooltip to every <app-icon-button> without the template opting in. See host elements.

Rendering components programmatically

When the component to show is only known at runtime, render it from code rather than from a static selector.

NgComponentOutlet does it declaratively in a template:

<ng-container *ngComponentOutlet="currentWidget()" />

ViewContainerRef.createComponent does it imperatively:

import { Component, ViewContainerRef, inject } from '@angular/core';
import { ChartWidget } from './chart-widget';

@Component({ selector: 'app-dashboard', template: `` })
export class Dashboard {
  private readonly vcr = inject(ViewContainerRef);

  show(): void {
    const ref = this.vcr.createComponent(ChartWidget);
    ref.setInput('title', 'Sales');
    // ref.destroy() to remove it
  }
}