Chapter 4.1โ˜• 15 min read

Custom Attribute Directives

Custom attribute directives let you create reusable element behaviors.

01What is a Custom Attribute Directive

Attribute directives change the appearance or behavior of an element. Built-in examples include ngClass and ngStyle โ€” but you can create your own!

"Custom directive = apna rule banao โ€” jaise traffic police ka custom signal." Just like a traffic police officer creates custom signals for specific situations, you create custom directives for specific UI behaviors.

Use cases: highlight an element on hover, change color based on validation, add tooltip behavior, detect clicks outside an element.

02Creating a Basic Directive

Creating a directive is easy with Angular CLI:

ng g d directives/highlight

This generates:

import { Directive } from '@angular/core';\n\n@Directive({\n  selector: '[appHighlight]',\n  standalone: true\n})\nexport class HighlightDirective implements OnInit {\n  // Your logic here\n}

Key points:

  • @Directive decorator โ€” marks the class as a directive
  • selector: '[appHighlight]' โ€” brackets mean it's an attribute selector
  • standalone: true โ€” works without NgModule in Angular 18
  • ng g d = "generate directive" โ€” creates the file automatically

"ElementRef = element ka Aadhaar card โ€” se sab access kar sakte ho."

03Using ElementRef and Renderer2

To access the DOM element inside a directive, inject ElementRef and optionally Renderer2:

constructor(private el: ElementRef, private renderer: Renderer2) {}\n\nngOnInit() {\n  // Direct DOM access โ€” โŒ Avoid if possible (breaks SSR)\n  this.el.nativeElement.style.backgroundColor = 'yellow';\n  \n  // Renderer2 โ€” โœ… Safe for SSR\n  this.renderer.setStyle(this.el.nativeElement, 'color', 'red');\n  this.renderer.addClass(this.el.nativeElement, 'highlighted');\n  this.renderer.setAttribute(this.el.nativeElement, 'data-id', '123');\n}

"ElementRef = direct touch, Renderer2 = gloves pehenke touch โ€” Renderer2 is safer for SSR."

Always prefer Renderer2 over direct ElementRef access โ€” it works in Service Workers and Server-Side Rendering (SSR).

04Directive with @Input โ€” Make it Configurable

Make your directive configurable with @Input:

@Input() appHighlight = 'yellow';  // Default color\n\nngOnInit() {\n  this.renderer.setStyle(this.el.nativeElement, 'background-color', this.appHighlight);\n}

Usage in template:

<p appHighlight="red">This has red background</p>\n<p appHighlight>This has yellow (default) background</p>\n<p [appHighlight]="userColor">Dynamic color from component</p>

"Input dalo toh custom color, nahi dalo toh default โ€” flexible bhai."

Note how the @Input name appHighlight matches the directive selector. This is a common pattern โ€” the directive itself becomes a property binding.

05Responding to User Actions

Respond to user actions with @HostListener:

@HostListener('mouseenter') onMouseEnter() {\n  this.renderer.setStyle(this.el.nativeElement, 'background-color', this.highlightColor);\n}\n\n@HostListener('mouseleave') onMouseLeave() {\n  this.renderer.setStyle(this.el.nativeElement, 'background-color', null);\n}\n\n@HostListener('click', ['$event']) onClick(event: MouseEvent) {\n  console.log('Clicked at:', event.clientX, event.clientY);\n}

"HostListener = CCTV camera โ€” element pe kya ho raha hai dekho."

Alternative: You can also use the host property in the @Directive decorator:

@Directive({\n  selector: '[appHighlight]',\n  host: {\n    '(mouseenter)': 'onMouseEnter()',\n    '(mouseleave)': 'onMouseLeave()'\n  },\n  standalone: true\n})

Key Takeaways

  • โœ… @Directive decorator creates custom attribute directives โ€” reusable element behaviors.
  • โœ… ElementRef gives access to the DOM element; Renderer2 is safer for SSR.
  • โœ… @Input() on the directive selector name makes it configurable.
  • โœ… @HostListener responds to user events on the host element.
  • โœ… Always use standalone: true in Angular 18 directives.
Course Search
Search across all chapters & stages
๐Ÿ“–

Search the course

Type any topic โ€” branching, stash, rebase, hooks โ€” and jump straight to that chapter.

merge branchesgit stashundo commitrebase