Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Angular’s Directive Composition API lets a component or directive apply other directives to its own host element. You list those directives in the hostDirectives property of the decorator, and Angular applies their host bindings to the composed element. The consuming template never needs to name the behavior’s selector. This article covers how the entries are declared, how inputs and outputs are exposed, the order in which everything runs, and the errors you are most likely to hit.

What the API does

Many UI features are a mix of behavior and markup. A menu might need keyboard handling, focus management and an open/closed state, while the component itself supplies the template. Before composition, teams usually copied that behavior into each component or asked consumers to add a second directive next to the component in their templates. hostDirectives moves that wiring into the component’s own metadata, so the consumer writes one element and receives the behavior with it.

The property belongs in the @Component or @Directive decorator. It is static metadata: Angular resolves it when the component is compiled. It is not a mechanism for adding behavior to an element at runtime. Also, the selector of a directive used as a host directive is ignored in this context. Whether that directive matches any selector in your app has no bearing on whether it is applied as a host directive.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A basic example

Suppose you have a reusable directive that manages the open state and keyboard behavior of a menu:

@Directive({
  selector: '[menuBehavior]',
})
export class MenuBehavior {
  // open state, keyboard handling, host bindings
}

A component can apply it to its own host element:

@Component({
  selector: 'app-side-menu',
  template: `<nav><ng-content /></nav>`,
  hostDirectives: [MenuBehavior],
})
export class SideMenu {}

Consumers write <app-side-menu> and do not add menuBehavior to the template. The behavior’s host bindings are applied to <app-side-menu>. Note, however, that nothing from MenuBehavior‘s public API is visible to consumers yet. That requires the next step.

Exposing inputs and outputs

Host-directive inputs and outputs are private to the composing component by default. A host directive can declare an input, but the component only exposes it when the composition metadata lists it. This distinction matters when you write examples or documentation: “the host directive has an input” and “the component exposes that input” are different statements.

Plain class entry

A bare class entry such as hostDirectives: [MenuBehavior] applies the directive and its host bindings, but it does not publish any of its inputs or outputs. Use it when the behavior needs no configuration from the consumer.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Object entry with inputs and outputs

To publish bindings, expand the entry to an object and name the bindings you want to expose:

@Component({
  selector: 'app-side-menu',
  template: `<nav><ng-content /></nav>`,
  hostDirectives: [{
    directive: MenuBehavior,
    inputs: ['menuId'],
    outputs: ['menuClosed'],
  }],
})
export class SideMenu {}

Consumers can now bind [menuId] and (menuClosed) on <app-side-menu>.

Renaming a binding with an alias

When the component should expose a clearer public name, use the originalName: alias form inside the same arrays:

hostDirectives: [{
  directive: MenuBehavior,
  inputs: ['menuId: id'],
  outputs: ['menuClosed: closed'],
}]

The consumer then writes <app-side-menu [id]="menuKey" (closed)="onClosed()">. The original names are no longer the public surface of the composed component.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Entry form Host bindings applied Inputs and outputs visible to consumers
Class entry: [MenuBehavior] Yes None
Object entry with inputs: ['menuId'] Yes menuId under its original name
Object entry with inputs: ['menuId: id'] Yes menuId published as id

Composing directives inside directives

A host directive can itself declare hostDirectives. This lets you build layered bundles: a low-level focus behavior, wrapped by a keyboard-navigation behavior, wrapped by a menu behavior, all applied to one component. Each layer exposes only the bindings its own composition metadata lists, so the outermost component controls what reaches the template.

Order of instantiation and host bindings

Host directives run before the component or directive that composes them. For a single level of composition, Angular proceeds in this order:

  1. The host directive is instantiated.
  2. The host directive receives its inputs and runs its initialization.
  3. The host directive’s host bindings are applied to the element.
  4. The owning component is instantiated and applies its own host bindings.

Nested chains keep this ordering from the innermost composed directive outward. The practical consequence is that when the owner and a host directive both write the same host binding, the owner’s binding is the one that takes effect. If you rely on a host directive to set a class or attribute, check that the owning component does not set the same thing.

Dependency injection between owner and host directives

The owner and its host directives can inject one another, so a host directive can read a service or token from the component that uses it, and the component can inject the behavior. When both the owner and one of its host directives provide the same token, the owner class’s provider takes precedence. Plan provider ownership accordingly: if the behavior should supply a token that the component overrides, provide it on the component.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Duplicate composition and NG8024

Repeated host-directive paths

The same directive can reach a component through more than one path, for example when two host directives each compose a shared focus behavior. Angular does not create two instances. It de-duplicates the matches, merges the directive into one instance, and combines the exposed input and output mappings from each path.

Template matches take precedence

If the same directive is also matched by a selector in a template, Angular keeps the template match and discards the host-directive matches. The template match carries the directive’s full public API, while host-directive matches only expose the bindings you configured.

Conflicting aliases: NG8024

Merging has one hard constraint. If merged paths expose a shared binding under different aliases, Angular reports error NG8024. The documented fixes are:

  • Make every path use the same alias for that binding.
  • Stop exposing the binding on one or both paths, so only one alias remains.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Choosing composition or another abstraction

Angular describes directives as the right tool for reusable behavior applied to existing elements or components. Typical examples are tooltips, autofocus, host-element classes and event handling. If the feature needs to render its own markup or manage a UI with its own template, a component, or a directive that has a template, is the better fit. The useful question is whether the element already exists in the consumer’s template and simply needs the behavior, or whether your abstraction owns the DOM it renders.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use composition when the consumer should get one element with a shared behavior, and when the behavior’s inputs and outputs can be curated for that element. Use a component when the structure of the markup is part of what you are packaging.

Version notes

Angular is a versioned framework, so confirm the rules for your release before copying a pattern. The current official guide states that a host directive may not specify standalone: false. Older versioned documentation phrases the same constraint as requiring standalone: true. Both describe the same boundary for their respective releases, so check the documentation for your exact Angular version when you are working on a project that has not been upgraded recently.

The examples above follow the current official guide, checked on 7 October 2026. The behavior of the alias syntax, de-duplication and NG8024 is described there; if your project uses an older release, look up the same sections in that release’s documentation.

“

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.