Components and templates

Standalone components, signal-based state, inputs and outputs, and the built-in template control flow.

A standalone component

npm install -g @angular/cli
ng new shop --style=scss --routing
cd shop && ng serve            # dev server on http://localhost:4200

ng generate component cart/item     # creates the four files for one component
ng generate service cart            # service skeleton with injectable metadata
// cart-item.component.ts
import { Component, input, output, signal, computed } from '@angular/core'
import { CurrencyPipe } from '@angular/common'

@Component({
  selector: 'app-cart-item',
  imports: [CurrencyPipe],              // standalone: only what this component uses
  template: `
    <li class="item" [class.active]="selected()">
      <span>{{ name() }}</span>
      <span>{{ price() | currency }}</span>
      <button (click)="pick.emit(id())" [disabled]="soldOut()">Add</button>
    </li>
  `
})
export class CartItemComponent {
  id = input.required<string>()
  name = input.required<string>()
  price = input(0)
  selected = input(false)
  soldOut = input(false)

  pick = output<string>()

  readonly label = computed(() => this.name().toUpperCase())
}
  • Standalone components declare their own dependencies in imports instead of being registered in an NgModule; recent versions treat standalone as the default.
  • input() and output() are signal-based: read an input by calling it, and emit by calling emit() on the output.
  • signal() holds local state and computed() derives from it; reading a signal in a template subscribes the view to it.
  • Decorator metadata is read at compile time, so keep the class body free of logic that a template should own.

Binding and control flow

<img [src]="avatarUrl()" [alt]="name() + ' avatar'">
<button (click)="add()" [disabled]="busy()">Add to cart</button>
<input [(ngModel)]="query" placeholder="Search">   <!-- needs FormsModule -->

@if (items().length) {
  <ul>
    @for (item of items(); track item.id) {
      <li>{{ item.name }} - {{ item.price | currency }}</li>
    } @empty {
      <li>No matches</li>
    }
  </ul>
} @else {
  <p>Nothing yet.</p>
}

@switch (status()) {
  @case ('draft') { <span>Draft</span> }
  @case ('live') { <span>Live</span> }
  @default { <span>Unknown</span> }
}
SyntaxDirectionExample
{{ }}Interpolation{{ total() }}
[prop]Component to DOM[disabled]="busy()"
(event)DOM to component(click)="save()"
[(ngModel)]Two-wayForm controls (template-driven)
@if / @for / @switchControl flowReplaced *ngIf and *ngFor
💡
The track expression in @for is required, and it is not ceremony: Angular uses it to move DOM nodes instead of destroying and recreating them when the list changes. Track a stable id, not the loop index.

Lifecycle and communication

import { Component, signal, computed, effect, afterNextRender, inject } from '@angular/core'
import { CartStore } from '../cart.store'

@Component({ selector: 'app-cart', template: '...' })
export class CartComponent {
  private cart = inject(CartStore)
  readonly total = computed(() => this.cart.items().reduce((t, i) => t + i.price, 0))

  constructor() {
    effect(() => console.log('items changed:', this.cart.items().length))

    afterNextRender(() => {
      // safe place for DOM measurement or a browser-only library
    })
  }
}
  • ngOnInit still works for class-based setup, but signals and effect() cover most of what ngOnChanges used to do.
  • effect() is for side effects that follow state, not for propagating state to other signals.
  • afterNextRender runs in the browser only, which keeps server-side rendering safe for DOM access.
  • Parents pass data down with inputs and listen upwards with outputs; avoid reading a child's internals from the parent.

FAQ

Do I need NgModules?
Not for new applications. Standalone components, directives and pipes are the current model; NgModules remain supported for existing code and third-party libraries that still export them.
signals or RxJS?
Signals for component state and derived values — they are synchronous, glitch-free and easy to read in a template. RxJS for streams of events over time: debounced input, websockets, complex cancellation.

Services and dependency injection Components, props and events

Last refreshed 2026-09-18.