On this page

Standalone components

15 min read TextCh. 1 — Fundamentals

Standalone components

In modern Angular (v17+), all components are standalone by default. You don't need NgModules to organize your application.

Anatomy of a component

A component has three parts:

  1. TypeScript class — The component's logic
  2. Template — The HTML view
  3. Styles — Encapsulated CSS

It is defined with the @Component decorator.

Component metadata

The @Component decorator receives an object with properties:

  • selector — The HTML tag name
  • template / templateUrl — The component's HTML
  • styles / styleUrl — The component's CSS
  • imports — Dependencies (other components, directives, pipes)
  • changeDetection — Change detection strategy

Inputs and Outputs

Components communicate with their parents through:

  • input() — To receive data from the parent
  • output() — To emit events to the parent

These replace the @Input and @Output decorators from previous versions.

// Required input
readonly name = input.required<string>();

// Input with default value
readonly role = input<string>('Student');

// Output (EventEmitter)
readonly selected = output<string>();

Practice

  1. Create a card component: Build a ProductCard component with an input() for the product name, another for the price, and an output() that emits when a "Buy" button is clicked.
  2. Use the component from a parent: Import ProductCard in another component and pass real data to it. Listen for the output event and log a message to the console.
  3. Add OnPush: Ensure your component uses ChangeDetectionStrategy.OnPush and verify it still works correctly.

In the next lesson, we will learn about Signals for managing state.

OnPush
Always use ChangeDetectionStrategy.OnPush. It improves performance by avoiding unnecessary template checks.
typescript
import { Component, input, output, ChangeDetectionStrategy } from '@angular/core';

@Component({
  selector: 'app-user-card',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <div class="card">
      <h3>{{ name() }}</h3>
      <p>{{ role() }}</p>
      <button (click)="selected.emit(name())">Select</button>
    </div>
  `,
  styles: `
    .card {
      padding: 1rem;
      border: 1px solid var(--border-color);
      border-radius: 0.75rem;
    }
  `,
})
export class UserCard {
  readonly name = input.required<string>();
  readonly role = input<string>('Student');
  readonly selected = output<string>();
}