Skip to content

Angular Attribute Directives

Attribute directives change the appearance or behavior of an existing element without adding or removing anything from the DOM. This lesson covers the built-in options and how to write your own.

What Is an Attribute Directive?

An attribute directive listens to an element's properties and events and modifies that same element in response, changing a style, a class, or an ARIA attribute, without creating or destroying any DOM nodes.

Angular ships two commonly used built-in attribute directives, ngClass and ngStyle, and lets you write custom ones with the @Directive decorator for any reusable DOM behavior.

<div
  [ngClass]="{ active: isActive, disabled: isDisabled }"
  [ngStyle]="{ color: isActive ? 'green' : 'gray' }"
>
  Status indicator
</div>

ngClass toggles the active and disabled classes based on booleans; ngStyle sets the color inline style dynamically.

Attribute Directive Syntax

[ngClass]="'class1 class2'"
[ngClass]="['class1', 'class2']"
[ngClass]="{ class1: cond1, class2: cond2 }"
[ngStyle]="{ 'font-size': size + 'px' }"
  • ngClass accepts a string, an array of class names, or an object mapping class names to booleans.
  • ngStyle accepts an object mapping CSS property names to values.
  • For a single conditional class or style, [class.name]/[style.prop] are simpler than ngClass/ngStyle.
  • Custom attribute directives use @Directive({ selector: '[appName]' }).

Attribute Directives Cheatsheet

Built-in directives plus the anatomy of a custom one.

Directive/API Example Purpose
ngClass (object) [ngClass]="{active: isActive}" Toggle multiple classes conditionally
ngStyle [ngStyle]="{color: c}" Set multiple inline styles
[class.x] [class.active]="isActive" Toggle a single class
@Directive @Directive({ selector: '[appFoo]' }) Define a custom directive
@Input() @Input() color = 'yellow'; Configure the directive from the template
@HostListener @HostListener('click') React to events on the host element
@HostBinding @HostBinding('class.active') Bind a property/class on the host element

A Custom Directive With an Input

Custom attribute directives can accept configuration through @Input() (or the newer input() function), just like components, making them reusable across different contexts.

import { Directive, Input, ElementRef, inject } from '@angular/core';

@Directive({
  selector: '[appHighlight]',
  standalone: true,
})
export class HighlightDirective {
  @Input() appHighlight = 'yellow';

  private el = inject(ElementRef);

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

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

Naming the input the same as the selector (appHighlight) lets you configure it inline: <p appHighlight="lightblue">.

@HostBinding vs Direct DOM Manipulation

@HostBinding lets you bind a class, style, or property on the host element declaratively, which Angular's change detection manages for you, generally preferable to manually mutating ElementRef.nativeElement, especially for server-side rendering compatibility.

import { Directive, HostBinding, Input } from '@angular/core';

@Directive({
  selector: '[appActiveClass]',
  standalone: true,
})
export class ActiveClassDirective {
  @Input() appActiveClass = false;

  @HostBinding('class.active')
  get isActive() {
    return this.appActiveClass;
  }
}

ngClass/ngStyle vs Single Bindings

For a single conditional class or style, [class.name]/[style.prop] bindings are simpler and slightly cheaper than ngClass/ngStyle. Reach for ngClass/ngStyle when you need to toggle several classes or styles together from one expression.

Common Mistakes

  • Reaching for ngClass with a single class when [class.name] would be simpler and clearer.
  • Manipulating ElementRef.nativeElement.style directly instead of using @HostBinding, which breaks in server-side rendering contexts.
  • Forgetting @Input() on a directive's configuration property, leaving it permanently at its default value.
  • Not cleaning up manually added event listeners in directives that don't use @HostListener.

Key Takeaways

  • Attribute directives change an existing element's appearance or behavior without altering DOM structure.
  • ngClass and ngStyle are built-in attribute directives for toggling multiple classes or styles at once.
  • Custom directives use @Directive, @Input(), @HostListener, and @HostBinding to build reusable behavior.
  • Prefer @HostBinding over direct DOM manipulation for better testability and SSR compatibility.

Pro Tip

Name a custom directive's primary @Input() the same as its selector (like appHighlight) so consumers can configure it inline on the same attribute, matching the ergonomics of Angular's own built-in directives.