Angular Directives — Structural and Attribute Guide
What are Directives in Angular?
Directives are one of Angular's most important building blocks. A directive is an instruction that tells Angular to change the structure, appearance, or behavior of elements in the DOM. In practical terms, directives are how Angular adds intelligence to HTML. They let templates do more than simply display static markup. A directive can show or hide a block, repeat a block, apply classes dynamically, or attach reusable behavior like highlighting, focus management, and keyboard handling.
Angular applications rely heavily on directives even when developers do not think about them explicitly. Every component is technically a kind of directive, built-in template controls are directive-driven, and many common UI behaviors are powered by attribute directives. Learning directives helps you understand how Angular templates become dynamic and interactive.
A Simple Mental Model
A useful way to think about directives is this: components create UI, directives modify UI. Some directives control whether an element exists at all, some change how an element looks, and some attach reusable behavior to an element. This is why directives are such a strong Angular pattern. They let you reuse behavior without copying the same code into many components.
Main Types of Directives
Component Directives
A component is a special type of directive that has its own template. Components are the main way Angular renders reusable sections of the UI. While people often discuss components separately from directives, it is useful to remember that components are actually directives with extra capabilities.
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
standalone: true,
template: `<h1>Tutorials Logic</h1>`
})
export class AppComponent {}
This is the directive type you use most in Angular because most screens are made from components. A component directive defines what should be rendered and how that piece of UI behaves.
Structural Directives
Structural directives change the DOM layout itself. They can add, remove, or repeat template blocks. Historically, Angular developers used directives like *ngIf, *ngFor, and *ngSwitch for these jobs. In modern Angular, the built-in control flow syntax @if, @for, and @switch is now the preferred approach in many cases.
The key idea is that structural directives do not merely style an element. They decide whether that element exists in the DOM and how many copies of it appear.
Built-in Control Flow (Angular 17+ / Angular 21)
Angular's newer built-in control flow syntax is more readable and fits well with modern Angular patterns. It replaces many uses of *ngIf, *ngFor, and *ngSwitch in new code.
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-root',
standalone: true,
template: `
@if (isLoggedIn()) {
<p>Welcome back!</p>
} @else {
<p>Please log in.</p>
}
<ul>
@for (item of items; track item.id) {
<li>{{ item.name }}</li>
} @empty {
<li>No items found.</li>
}
</ul>
@switch (status()) {
@case ('active') { <span style="color:green">Active</span> }
@case ('inactive') { <span style="color:red">Inactive</span> }
@default { <span>Unknown</span> }
}
<button (click)="toggle()">Toggle Login</button>
`
})
export class AppComponent {
isLoggedIn = signal(false);
status = signal('active');
items = [
{ id: 1, name: 'Angular' },
{ id: 2, name: 'React' },
{ id: 3, name: 'Vue' }
];
toggle() {
this.isLoggedIn.update(v => !v);
}
}
This example shows three important structural ideas. @if controls whether a block appears. @for repeats a block for a collection. @switch chooses one block from many alternatives. Together, these patterns cover a large part of everyday Angular template logic.
Older Structural Directives
Many real Angular codebases still use the older star-syntax structural directives, so it is important to recognize them even if newer syntax is preferred in fresh code.
<p *ngIf="isLoggedIn">Welcome back!</p>
<ul>
<li *ngFor="let item of items">{{ item.name }}</li>
</ul>
When reading older Angular tutorials or enterprise projects, you will still see these often. Understanding both styles will make you much more comfortable in real codebases.
Attribute Directives
Attribute directives change the appearance or behavior of an existing element without replacing the whole template. They do not create or remove DOM blocks like structural directives do. Instead, they influence an already existing element by changing classes, styles, disabled states, and similar behavior.
Common built-in examples include [ngClass] and [ngStyle]. These are used frequently when UI styling depends on runtime conditions.
import { Component, signal } from '@angular/core';
import { NgClass, NgStyle } from '@angular/common';
@Component({
selector: 'app-root',
standalone: true,
imports: [NgClass, NgStyle],
template: `
<p [ngClass]="{ 'active': isActive, 'bold': isBold }">
Styled with ngClass
</p>
<p [ngStyle]="{ 'color': textColor(), 'font-size': '18px' }">
Styled with ngStyle
</p>
<button (click)="toggleActive()">Toggle Active</button>
`,
styles: ['.active { background: #e8f5e9; } .bold { font-weight: bold; }']
})
export class AppComponent {
isActive = true;
isBold = false;
textColor = signal('blue');
toggleActive() {
this.isActive = !this.isActive;
}
}
Attribute directives are especially helpful for status styling, theme changes, validation feedback, dynamic button states, and conditional classes that would otherwise require repetitive template code.
Custom Directives
Custom directives are directives that you create yourself to encapsulate reusable behavior. This is valuable when the same behavior needs to be applied across many components or templates. Instead of repeating host listeners, style changes, or DOM-related logic in multiple places, you can create one custom directive and apply it wherever needed.
Good custom directive use cases include hover highlighting, auto-focus behavior, permission-based disabling, drag/drop helpers, keyboard shortcuts, and custom validation UI effects.
import { Directive, ElementRef, HostListener, input } from '@angular/core';
@Directive({
selector: '[appHighlight]',
standalone: true
})
export class HighlightDirective {
color = input('yellow', { alias: 'appHighlight' });
constructor(private el: ElementRef<HTMLElement>) {}
@HostListener('mouseenter')
onEnter() {
this.el.nativeElement.style.backgroundColor = this.color();
}
@HostListener('mouseleave')
onLeave() {
this.el.nativeElement.style.backgroundColor = '';
}
}
import { Component } from '@angular/core';
import { HighlightDirective } from './highlight.directive';
@Component({
selector: 'app-root',
standalone: true,
imports: [HighlightDirective],
template: `
<p appHighlight="lightblue">Hover over me!</p>
<p appHighlight>Hover - default yellow</p>
`
})
export class AppComponent {}
This example is a good illustration of why directives are useful. The hover behavior becomes reusable and easy to apply across many different elements without repeating the same event handling logic.
Directive Selectors
Directives use selectors to define where they should apply. A selector like [appHighlight] means the directive is activated when that attribute appears on an element. This is why many custom directives use attribute selectors: they attach behavior without changing the overall structure of the markup.
Choosing good selector names is important. A clear selector such as appHighlight, appAutoFocus, or appPermissionGuard communicates intent much better than a vague name.
Directives and the DOM
Some directives interact directly with the DOM through tools like ElementRef, Renderer2, and HostListener. While this is sometimes necessary, direct DOM access should be used with care. Whenever Angular bindings can handle the job more safely, they are usually preferred. For example, a class binding or style binding may be better than direct style mutation if the effect is simple.
Custom directives are most valuable when the behavior is reusable enough that it would be awkward or repetitive to express with inline bindings alone.
When to Use a Directive vs a Component
A component should be used when you need a new piece of UI with its own template. A directive should be used when you want to change the behavior or styling of an existing element without creating a separate view block.
For example, if you want to build a reusable user card with markup, labels, and layout, a component is the right fit. If you want any element to highlight on hover or auto-focus when shown, a directive is a better fit. This distinction helps keep Angular code well-structured.
Directives in Modern Angular
Modern Angular keeps directives highly relevant even though syntax continues to evolve. The new built-in control flow syntax reduces the need to write some older structural directive forms manually, but attribute directives and custom directives remain extremely useful. Standalone APIs also make directives easier to import and reuse without wrapping everything inside NgModules.
This means directives are still a core Angular skill. Even as the framework becomes more ergonomic, the underlying concept of attaching structure and behavior to templates is still central.
Common Beginner Mistakes
Summary
Directives are how Angular teaches HTML new behavior. Some directives define full reusable UI blocks, some change the DOM structure, and others add behavior or styling to existing elements. Once you understand the difference between component directives, structural directives, attribute directives, and custom directives, Angular templates become much easier to read and design. Directives are one of the framework's most powerful tools for keeping UI behavior reusable and expressive.
- Directives are Angular instructions that change the structure, appearance, or behavior of DOM elements.
- Components are a special type of directive with their own template.
- Structural directives control whether elements exist and how many times they appear.
- Attribute directives change the behavior or styling of existing elements.
- Custom directives are useful for reusable DOM behavior such as highlighting, focus handling, and interaction rules.
-
Modern Angular often uses
@if,@for, and@switchinstead of older structural directive syntax in new code.
Level Up Your Angular Skills
Master Angular with these hand-picked resources