Reader Stacks

Types of Directives in Angular: Components, Structural, and Attribute

Every component in Angular is technically a directive too — understanding the three-way split (component, structural, attribute) clarifies why *ngIf, [ngClass], and a custom component all count as the same underlying concept.

"Directive" is a broader category in Angular than it might first appear — every custom component is technically a directive with a template attached. Angular groups directives into three types based on what they actually do to the DOM, and knowing which category something falls into clarifies a lot about how it's meant to be used.

1. Component directives

@Component({
  selector: 'app-product-card',
  template: `<div class="card">{{ product.name }}</div>`,
})
export class ProductCardComponent {
  @Input() product!: Product;
}

A component is a directive with its own template — the most familiar and heavily-used kind, but structurally it's still a directive at its core, just one that renders its own markup rather than modifying an existing element.

2. Structural directives — add or remove elements from the DOM

<div *ngIf="isVisible">Shown conditionally</div>
<li *ngFor="let item of items">{{ item.name }}</li>

Covered in more depth in an earlier look at *ngIf and *ngFor specifically — structural directives are marked with a leading * and change the actual DOM structure: adding, removing, or repeating elements entirely, not just adjusting an existing element's appearance.

3. Attribute directives — change appearance or behavior of an existing element

<p [ngClass]="{ 'is-active': isActive }">Text</p>
<p appHighlight>Custom directive example</p>

Also covered in more detail in building custom directives — an attribute directive modifies the element it's applied to (styling, behavior, event handling) without adding or removing anything from the DOM structure itself, which is the key distinction from a structural directive.

4. Why the three-way split matters practically

Recognizing which category a given directive falls into predicts how it behaves and how it's written: a structural directive needs the * syntax (or the more verbose <ng-template> form it desugars to) and typically implements TemplateRef/ViewContainerRef logic to add or remove DOM; an attribute directive is generally simpler, working through ElementRef and @HostListener/@HostBinding to affect an element already present in the DOM.

5. How ngModel fits into this

<input [(ngModel)]="username">

ngModel is an attribute directive — it doesn't add or remove the input element from the DOM; it attaches two-way binding behavior (reading and writing the input's value) to an element that's already there, which is exactly the attribute-directive pattern: modifying behavior on an existing element rather than controlling whether that element exists at all.

6. A quick reference

TypePurposeExamples
ComponentHas its own templateAny custom @Component
StructuralAdds/removes DOM elements*ngIf, *ngFor, *ngSwitch
AttributeChanges appearance/behavior of an existing elementngClass, ngStyle, ngModel, custom directives

Understanding this taxonomy is mostly useful for deciding what to build when creating something custom — a reusable piece of markup is a component; reusable conditional DOM logic is a structural directive; reusable behavior attached to existing markup is an attribute directive.

Topics: Developer Productivity