Angular Directives

Directives let you attach extra behavior to DOM elements, and Angular splits them into structural directives that reshape the DOM and attribute directives that modify an existing element.

#Jobseeker

Find matching jobs & Auto apply with AI

Hyring
Jobseeker using Hyring to search, apply, and prepare with AI

What Directives Do

A directive is a class that runs logic against a host element in the template, without necessarily rendering its own markup the way a component does. In fact, every component is technically a directive with a template attached. Angular ships several built-in directives and lets you write your own.

Structural Directives

Structural directives change the shape of the DOM by adding, removing, or repeating elements entirely. They are traditionally written with a leading asterisk, like *ngIf and *ngFor, which is shorthand Angular expands into an <ng-template>. Modern Angular also offers built-in control flow blocks such as @if and @for that achieve the same result with cleaner syntax and better type-checking.

Structural directive: *ngFor rendering a list

import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { bootstrapApplication } from '@angular/platform-browser';

@Component({
  selector: 'app-task-list',
  standalone: true,
  imports: [CommonModule],
  template: `
    <ul>
      <li *ngFor="let task of tasks; index as i">
        {{ i + 1 }}. {{ task }}
      </li>
    </ul>
  `
})
export class TaskListComponent {
  tasks = ['Write report', 'Review PR', 'Deploy build'];
}

bootstrapApplication(TaskListComponent).catch((err) => console.error(err));

Attribute Directives

Attribute directives change the appearance or behavior of an element without adding or removing it from the DOM. NgClass and NgStyle are the most common built-ins, letting you toggle CSS classes or inline styles based on component state.

Attribute directive: NgClass toggling styles

import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { bootstrapApplication } from '@angular/platform-browser';

@Component({
  selector: 'app-status-badge',
  standalone: true,
  imports: [CommonModule],
  template: `
    <span [ngClass]="{ active: isActive, inactive: !isActive }">
      {{ isActive ? 'Active' : 'Inactive' }}
    </span>
  `
})
export class StatusBadgeComponent {
  isActive = true;
}

bootstrapApplication(StatusBadgeComponent).catch((err) => console.error(err));
DirectiveCategoryWhat it does
*ngIf / @ifStructuralAdds or removes an element based on a condition
*ngFor / @forStructuralRepeats an element once per item in a collection
ngSwitch / @switchStructuralRenders one of several branches based on a value
ngClassAttributeToggles one or more CSS classes
ngStyleAttributeSets one or more inline style properties

Writing a Custom Attribute Directive

You are not limited to the built-ins. A custom directive is just a class decorated with @Directive that injects ElementRef or listens for host events to change how an element behaves.

A custom highlight directive

import { Component, Directive, ElementRef, HostListener } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';

@Directive({
  selector: '[appHighlight]',
  standalone: true
})
export class HighlightDirective {
  constructor(private el: ElementRef) {}

  @HostListener('mouseenter')
  onEnter() {
    this.el.nativeElement.style.backgroundColor = 'yellow';
  }

  @HostListener('mouseleave')
  onLeave() {
    this.el.nativeElement.style.backgroundColor = '';
  }
}

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [HighlightDirective],
  template: `
    <p appHighlight>Hover over this text to see the highlight directive in action.</p>
  `
})
export class AppComponent {}

bootstrapApplication(AppComponent).catch((err) => console.error(err));
  • Structural directives reshape the DOM tree; attribute directives only touch the element they sit on.
  • Only one structural directive can be applied per host element — combine *ngIf and *ngFor by wrapping one in an <ng-container>.
  • Custom directive selectors are usually written in square brackets, like [appHighlight], so they apply as an attribute rather than a new tag.
  • The newer @if / @for / @switch control-flow blocks do not require importing CommonModule at all.
Note: Behind the scenes, *ngIf="condition" desugars to <ng-template [ngIf]="condition">, which is why you will occasionally see ng-template referenced in compiler error messages even though you never typed it yourself.
Note: CommonModule must be in a standalone component's imports array to use *ngIf, *ngFor, ngClass, or ngStyle — a missing import here produces a template error claiming the directive is not a known attribute.

Exercise: Angular Directives

What distinguishes structural directives from attribute directives?