Skip to content

Angular Components Explained — Complete Guide to Building Reusable UI

DodaTech Updated 2026-06-28 7 min read

In this tutorial, you will learn about Angular Components Explained. We cover key concepts, practical examples, and best practices to help you master this topic.

Angular components are the building blocks of any Angular application, encapsulating template logic, styles, and behavior into reusable, testable units.

What You'll Learn

  • What Angular components are and why they matter
  • How to create components with the Angular CLI
  • How selectors, templates, and styles work together
  • How to pass data with @Input and emit events with @Output
  • How to compose complex UIs from small components

Why It Matters

Components let you break a complex UI into small, independent pieces that are easier to build, test, and maintain. Every Angular app is a tree of components, and mastering them unlocks the full power of the framework.

Real-World Use

Think of a dashboard like the Durga Antivirus Pro control panel. The threat graph is one component, the scan button is another, and the file list is a third. Each is built and tested in isolation, then composed into a full page.

flowchart TD
    A[App Root] --> B[Header]
    A --> C[Sidebar]
    A --> D[Main Content]
    D --> E[Threat Graph]
    D --> F[Scan Controls]
    D --> G[File List]
    style A fill:#f97316,color:#fff

What Is an Angular Component?

A component controls a patch of screen called a view. It consists of three things:

  1. A TypeScript class that handles data and logic
  2. An HTML template that declares what renders
  3. CSS styles scoped to that component

Think of a component like a stamp. The class is the stamp's handle (you grip it), the template is the rubber face that leaves an impression, and the styles are the ink color.

The @Component Decorator

Every component starts with the @Component decorator, which tells Angular the metadata it needs:

import { Component } from "@angular/core";

@Component({
  selector: "app-greeting",
  standalone: true,
  template: `
    <h1>Hello, {{ name }}!</h1>
    <p>Welcome to Angular components.</p>
  `,
  styles: [`
    h1 { color: #f97316; font-family: sans-serif; }
    p { font-size: 1.1rem; }
  `]
})
export class GreetingComponent {
  name = "Angular Developer";
}

Expected output: A page with "Hello, Angular Developer!" in orange and a subtitle below.

The selector is the custom HTML tag you use to place this component. When Angular sees <app-greeting></app-greeting> in another template, it renders this component's view.

Using a Component

Once created, you use a component by adding its tag to another template:

import { Component } from "@angular/core";
import { GreetingComponent } from "./greeting/greeting.component";

@Component({
  selector: "app-root",
  standalone: true,
  imports: [GreetingComponent],
  template: `
    <app-greeting></app-greeting>
    <p>This is the root component.</p>
  `
})
export class AppComponent {}

Expected output: The greeting component renders above the root component's text.

The imports array tells Angular that AppComponent depends on GreetingComponent. Without it, Angular would not know what <app-greeting> means.

Passing Data with @Input

Components often need data from their parent. Use the @Input decorator to define a property that accepts incoming values:

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

@Component({
  selector: "app-user-card",
  standalone: true,
  template: `
    <div class="card">
      <h3>{{ name }}</h3>
      <p>{{ email }}</p>
      <span class="badge" [style.background]="active ? "green" : "gray"">
        {{ active ? "Active" : "Inactive" }}
      </span>
    </div>
  `,
  styles: [`
    .card { border: 1px solid #ddd; padding: 16px; border-radius: 8px; }
    .badge { color: white; padding: 4px 8px; border-radius: 4px; font-size: 0.8rem; }
  `]
})
export class UserCardComponent {
  @Input() name = "";
  @Input() email = "";
  @Input() active = false;
}

The parent uses property binding to pass values:

<app-user-card [name]="user.name" [email]="user.email" [active]="user.active"></app-user-card>

Expected output: A card displaying the user's name, email, and a colored active/inactive badge.

The brackets [] around the property tell Angular this is a property binding, not a static attribute. The value inside quotes is a JavaScript expression evaluated against the parent component.

Emitting Events with @Output

Components notify their parent about events using @Output with EventEmitter:

import { Component, Input, Output, EventEmitter } from "@angular/core";

@Component({
  selector: "app-counter",
  standalone: true,
  template: `
    <div>
      <p>Count: {{ count }}</p>
      <button (click)="increment()">+</button>
      <button (click)="reset.emit()">Reset</button>
    </div>
  `
})
export class CounterComponent {
  @Input() count = 0;
  @Output() countChange = new EventEmitter<number>();
  @Output() reset = new EventEmitter<void>();

  increment() {
    this.countChange.emit(this.count + 1);
  }
}

The parent listens to events with parentheses:

<app-counter [count]="counterValue" (countChange)="counterValue = $event" (reset)="counterValue = 0"></app-counter>

Expected output: A counter that increments when the plus button is clicked and resets when the reset button is clicked.

The $event variable holds whatever was emitted. For countChange, it is a number. Angular's event binding syntax (eventName) matches the @Output() property name.

Common Mistakes

  1. Forgetting to import a component — If Angular throws an error like "app-greeting is not a known element", you forgot to add the component to the imports array of the parent.

  2. Using @Input without brackets in the template — Writing <app-card name="user.name"> passes the literal string "user.name", not the value of the variable. Use [name]="user.name" instead.

  3. Mutating @Input properties directly — Input properties should be treated as read-only. If you need to modify the value, emit an event and let the parent handle the change.

  4. Selectors that clash with native HTML — Always prefix your selectors (e.g., app- or cmp-). A selector named card could conflict with future HTML elements or third-party components.

  5. Putting logic in the template — Templates should only contain expressions, not statements. Fetching data, transforming values, or calling methods that modify state should happen in the class.

Practice Questions

  1. What three parts make up an Angular component? The TypeScript class (logic), the HTML template (view), and the CSS styles (presentation).

  2. What does standalone: true mean in a component? The component manages its own dependencies via the imports array instead of requiring a parent NgModule.

  3. How do you pass a string to a component's @Input? Use property binding: <app-child [inputName]="'string value'"></app-child> or <app-child inputName="string value"></app-child> for static strings.

  4. What is the difference between @Input and @Output? @Input lets a parent pass data into the component. @Output lets the component emit events back to the parent.

  5. What happens if you forget the imports array? Angular throws a template parse error because it does not recognize the child component's selector.

Challenge

Build a ProductCardComponent with @Input() for name, price, and inStock (boolean). Use @Output() to emit an addToCart event. The card should show a gray "Out of Stock" badge when inStock is false and a green "Add to Cart" button when true. Compose three product cards in the root component.

FAQ

What is the difference between a component and a directive?

A component is a directive with a template. Components always have a view; directives add behavior to existing elements.

Can a component exist without a selector?

Yes, route components often define a path but not a selector. They are rendered by the router, not by another template.

How do I nest components?

Add the child component's selector tag inside the parent component's template and import the child in the parent's imports array.

What is the component lifecycle?

Angular calls lifecycle methods like ngOnInit, ngOnChanges, and ngOnDestroy at specific moments from creation to destruction.

Can I use multiple components in one file?

You can define multiple classes in one file, but each must be exported and have its own @Component decorator with a unique selector.

Mini Project

Build a TaskBoardComponent that displays a list of tasks. Create a TaskCardComponent with @Input() for title, description, priority (high/medium/low), and completed (boolean). Use @Output() to emit a toggleComplete event. The board should show three columns for each priority level. Style cards with colored borders based on priority.

// task-card.component.ts
import { Component, Input, Output, EventEmitter } from "@angular/core";

@Component({
  selector: "app-task-card",
  standalone: true,
  template: `
    <div class="task-card" [style.border-left]="borderColor">
      <h4>{{ title }}</h4>
      <p>{{ description }}</p>
      <button (click)="toggle.emit()">
        {{ completed ? "Undo" : "Complete" }}
      </button>
    </div>
  `,
  styles: [`
    .task-card { padding: 12px; margin: 8px 0; border: 1px solid #ddd; border-radius: 6px; }
  `]
})
export class TaskCardComponent {
  @Input() title = "";
  @Input() description = "";
  @Input() priority: "high" | "medium" | "low" = "medium";
  @Input() completed = false;
  @Output() toggle = new EventEmitter<void>();

  get borderColor() {
    return this.priority === "high" ? "4px solid #ef4444"
         : this.priority === "medium" ? "4px solid #f97316"
         : "4px solid #22c55e";
  }
}

What's Next

Now that you understand components, learn how templates and data binding work:

Angular Templates, Angular Directives, Angular Services

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro