Logo

Angular Core

Directives

Think of directives as superpowers for your HTML elements. They change the appearance or behavior of any tag without you having to build a completely new component.

Components are great, but sometimes they are overkill. If I just want an image to have a "lazy load" effect, or an input field to automatically focus when the page loads, I don't want to wrap them in a
<my-wrapper> component.

That's why I love Directives. They act like "plugins" or "mixins" for your HTML. I write the logic once (e.g., "Make background colorful on hover") and can then attach this capability to any element in my app—whether it's a <div>, a <button>, or another component.

1. The Simulation

I built a simple [appHighlight] directive here. Select a color and hover over the box. Notice that the HTML element itself is dumb; the color logic comes entirely from the directive attached to it.

Directive Configuration:
<div [appHighlight]="#FCD34D">
👆 Hover me! Background Color applied via Renderer2

2. Implementation

Building a directive is simpler than a component because it has no template. It only has logic. The core concepts you need to know are ElementRef (to touch the DOM) and @HostListener (to react to the user).

Step 1: The Logic (Directive)

This is the blueprint. By using selector: '[appHighlight]', Angular knows to activate this class whenever it sees that attribute in your HTML.

highlight.directive.ts
import { Directive, ElementRef, HostListener, Input, inject } from '@angular/core';

@Directive({
  // The square brackets [] mean: This is used as an attribute.
  // Usage: <div appHighlight>...</div>
  selector: '[appHighlight]',
  standalone: true
})
export class HighlightDirective {
  // Access the DOM element this directive is attached to
  private el = inject(ElementRef);

  // Allow configuration from outside (e.g. appHighlight="blue")
  @Input() appHighlight = '';

  // Listen to native events on the host element
  @HostListener('mouseenter') onMouseEnter() {
    this.setColor(this.appHighlight || 'yellow');
  }

  @HostListener('mouseleave') onMouseLeave() {
    this.setColor('');
  }

  private setColor(color: string) {
    this.el.nativeElement.style.backgroundColor = color;
    this.el.nativeElement.style.transition = 'background-color 0.3s';
  }
}

Step 2: usage (HTML)

Now we can attach the behavior. A neat trick is using the Input Alias: By naming the @Input() variable the same as the selector, we can pass the color directly in the attribute.

usage.html
<!-- 1. Simple usage (default color) -->
<p appHighlight>
  Hover me (Default)
</p>

<!-- 2. Passing a value (custom color) -->
<!-- Note: We assign the string 'cyan' directly to the directive -->
<div appHighlight="cyan" class="box">
  I turn cyan on hover.
</div>

<!-- 3. Works on any tag -->
<button appHighlight="#ff00ff">
  Even Buttons!
</button>
💡

Attribute vs. Structural: What we built here is an Attribute Directive (changes look/behavior).
There are also Structural Directives (recognizable by the asterisk * like *ngIf or *ngFor). These are more powerful as they can physically add or remove elements from the DOM.