Jede Angular-Komponente wird in ein HTML-Element im DOM gerendert – dieses Element nennt man das Host-Element (z. B. <app-button>). Während du im Template der Komponente vollen Zugriff auf das Innere der Komponente hast, musst du spezielle Techniken anwenden, um Attribute, Klassen oder Events direkt auf dem Host-Element selbst zu setzen. Dieser Artikel zeigt dir die modernen und klassischen Methoden dafür.

Binding mit der host Eigenschaft (Modern)

Der von Angular empfohlene Weg, um mit dem Host-Element zu interagieren, ist die host-Eigenschaft innerhalb des @Component-Dekorators. Sie bündelt alle Host-Bindings übersichtlich an einem Ort.

Du kannst dort statische Attribute, dynamische Bindings (wie Klassen oder Styles) und Event-Listener definieren.

TypeScript custom-slider.component.ts
import { Component, signal } from '@angular/core';

@Component({
    selector: 'app-custom-slider',
    template: `<div>Slider Inhalt</div>`,
    host: {
        // Statisches Attribut (wird immer so gerendert: role="slider")
        'role': 'slider',

        // Dynamisches Klassen-Binding (Klasse 'active' wird gesetzt, wenn isActive() true ist)
        '[class.active]': 'isActive()',

        // Dynamisches Style-Binding
        '[style.background]': `hasError() ? 'red' : 'green'`,

        // Attribut-Binding
        '[attr.aria-valuenow]': 'value',

        // Event-Listener (lauscht auf Tastatur-Events auf dem Host-Tag)
        '(keydown)': 'updateValue($event)'
    },
    standalone: true
})
export class CustomSliderComponent {
    value: number = 0;
    isActive = signal(false);
    hasError = signal(false);

    updateValue(event: KeyboardEvent) {
        // Event verarbeiten
    }
}

Globale Event-Listener

Du kannst über die host-Eigenschaft auch auf globale Events wie das window oder document lauschen:

TypeScript host-global.ts
host: {
    // Lauscht auf Scroll-Events des gesamten Fensters
    '(window:scroll)': 'onWindowScroll($event)',
    // Lauscht auf Klicks irgendwo im Dokument
    '(document:click)': 'onDocumentClick($event)'
}

@HostBinding und @HostListener (Klassisch)

In vielen bestehenden Projekten findest du stattdessen die Dekoratoren @HostBinding und @HostListener. Sie funktionieren exakt genauso wie die host-Eigenschaft, verteilen die Logik aber über die gesamte TypeScript-Klasse.

TypeScript legacy-host.ts
import { Component, HostBinding, HostListener } from '@angular/core';

@Component({
    selector: 'app-legacy-slider',
    template: `...`
})
export class LegacySliderComponent {
    // Bindet die Eigenschaft "value" an das aria-valuenow Attribut des Hosts
    @HostBinding('attr.aria-valuenow') value: number = 0;

    // Dynamisches Setzen des tabIndex
    @HostBinding('tabIndex') get tabIndex() {
        return this.isDisabled ? -1 : 0;
    }
    isDisabled = false;

    // Lauscht auf keydown Events des Hosts
    @HostListener('keydown', ['$event'])
    updateValue(event: KeyboardEvent) {
        // ...
    }
}

Kollisionen: Wer gewinnt?

Es kann vorkommen, dass eine Komponente ein Host-Binding definiert, der Entwickler aber beim Verwenden der Komponente dasselbe Attribut nochmals von außen setzt.

Beispiel – Die Komponente definiert intern:

TypeScript photo.component.ts
host: { 'role': 'presentation', '[id]': 'id' }

Und wird im HTML so aufgerufen:

HTML photo-usage.html
<app-photo role="group" [id]="otherId" />

Die Regeln zur Konfliktauflösung lauten:

  1. Wenn beide Werte statisch sind (role="presentation" intern vs. role="group" extern), gewinnt der äußere (externe) Wert.
  2. Wenn ein Wert statisch und der andere dynamisch ist, gewinnt der dynamische Wert.
  3. Wenn beide Werte dynamisch sind, gewinnt das interne Host-Binding der Komponente.

Statische Attribute auslesen (HostAttributeToken)

Wenn du in deiner Komponente ein statisches HTML-Attribut (kein Input-Binding!) auslesen möchtest, das der Host-Komponente übergeben wurde, kannst du das HostAttributeToken zusammen mit inject() verwenden.

Das ist sehr performant, da Angular hierfür keinen Change-Detection-Zyklus benötigt.

TypeScript host-attribute.ts
import { Component, HostAttributeToken, inject } from '@angular/core';

@Component({
    selector: 'app-button',
    template: `<button>Klick mich</button>`,
    standalone: true
})
export class ButtonComponent {
    // Liest das statische Attribut "variation" aus (z.B. <app-button variation="primary">)
    // Wirft einen Fehler, wenn das Attribut fehlt!
    variation = inject(new HostAttributeToken('variation'));
    
    // Mit optionalem Fallback:
    // variation = inject(new HostAttributeToken('variation'), { optional: true }) ?? 'default';
}

Besonderheiten

hostDirectives als Komposition

Seit Angular 15 kannst du im @Component-Dekorator über hostDirectives: [...] mehrere Direktiven direkt am Host anbringen, ohne sie im Template einbauen zu müssen. Das ist die saubere Alternative zur klassischen Mehrfach-Vererbung und lässt sich mit Input-/Output-Aliassen feingranular steuern.

Globale Targets "document", "window", "body"

Event-Listener im host-Objekt akzeptieren die Präfixe document:, window: und body: – z. B. '(window:resize)': 'onResize($event)'. So bekommst du globale Listener ohne manuelles addEventListener samt automatischem Cleanup.

CSS-Custom-Properties als Bindings

Im host-Objekt (und mit @HostBinding) kannst du auch CSS-Variablen binden, etwa '[style.--accent]': 'color()'. Damit reichst du Signal-Werte ohne manuelle DOM-Manipulation an Child-Styles weiter – ideal für Theming.

Dekoratoren nur noch für Legacy

Die Doku formuliert es deutlich: @HostBinding und @HostListener existieren ausschließlich aus Gründen der Rückwärtskompatibilität. Für neuen Code immer die host-Property nutzen – sie ist auch Voraussetzung für künftige Performance-Optimierungen des Compilers.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Komponenten-Interaktion

Zur Übersicht