# ng-dynamic-component

> > Dynamic components with full life-cycle support for inputs and outputs

Latest version **11.0.0** (published 2026-07-17) · MIT license · 0 weekly downloads

## Install

```sh
npm install ng-dynamic-component
pnpm add ng-dynamic-component
yarn add ng-dynamic-component
bun add ng-dynamic-component
```

## Health

**Score 65/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; has provenance; recently updated.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 11.0.0 |
| Published | 2026-07-17 |
| First published | 2017-02-16 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 1 |
| Unpacked size | 510.9 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| GitHub stars | 559 |
| Author | Alex Malkevich |
| Maintainers | gund |
| Keywords | angular, angular2, ng, dynamic, component, input, output, life-cycle |

## Links

- npm: https://www.npmjs.com/package/ng-dynamic-component
- Repository: https://github.com/gund/ng-dynamic-component
- Homepage: https://github.com/gund/ng-dynamic-component#readme
- Issues: https://github.com/gund/ng-dynamic-component/issues
- npm.io page: https://npm.io/package/ng-dynamic-component

## Dependencies (1)

- [tslib](https://npm.io/package/tslib.md) ^2.0.0

## Alternatives

- [angular-pipes](https://npm.io/package/angular-pipes.md) — 5.6K weekly downloads
- [@ng-web-apis/midi](https://npm.io/package/@ng-web-apis/midi.md) — 2.6K weekly downloads
- [happn-3](https://npm.io/package/happn-3.md) — 1.6K weekly downloads
- [@opensip-cli/lang-go](https://npm.io/package/@opensip-cli/lang-go.md) — 1.2K weekly downloads
- [mongoose-typescript](https://npm.io/package/mongoose-typescript.md) — 85 weekly downloads

## Recent versions

- 11.0.0 (latest) — 2026-07-17
- 10.8.0-next.1 (next) — 2024-12-17
- 10.1.1-no-barrels.1 (no-barrels) — 2021-12-17
- 6.1.1-channel-ivy-ivy.2 (channel-ivy) — 2020-04-14
- 1.0.0-beta.4 (beta) — 2017-02-18
- 10.8.2 — 2025-01-21
- 10.8.1 — 2025-01-09
- 10.8.0 — 2025-01-07
- 10.7.0 — 2023-03-15
- 10.6.2 — 2023-03-15
- 10.6.1 — 2023-01-26
- 10.6.0 — 2023-01-25
- 10.5.1 — 2022-09-01
- 10.5.1-next.1 — 2022-09-01
- 10.5.0 — 2022-08-29
- … 86 more at https://npm.io/package/ng-dynamic-component/versions

## README

# ng-dynamic-component

> Dynamic components with full life-cycle support for inputs and outputs

[![Release Workflow](https://github.com/gund/ng-dynamic-component/actions/workflows/release.yml/badge.svg)](https://github.com/gund/ng-dynamic-component/actions/workflows/release.yml)
[![Test Workflow](https://github.com/gund/ng-dynamic-component/actions/workflows/test.yml/badge.svg)](https://github.com/gund/ng-dynamic-component/actions/workflows/test.yml)
[![Coverage](https://codecov.io/gh/gund/ng-dynamic-component/branch/master/graph/badge.svg?token=BjOghV9KX8)](https://codecov.io/gh/gund/ng-dynamic-component)
[![Maintainability](https://api.codeclimate.com/v1/badges/df4884f0ef7b49c285d0/maintainability)](https://codeclimate.com/github/gund/ng-dynamic-component/maintainability)
[![Npm](https://img.shields.io/npm/v/ng-dynamic-component.svg?maxAge=2592000)](https://badge.fury.io/js/ng-dynamic-component)
[![Npm Downloads](https://img.shields.io/npm/dt/ng-dynamic-component.svg?maxAge=2592000)](https://www.npmjs.com/package/ng-dynamic-component)
[![Licence](https://img.shields.io/npm/l/ng-dynamic-component.svg?maxAge=2592000)](https://github.com/gund/ng-dynamic-component/blob/master/LICENSE)
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)

### Hey! There is a [proposal for new API](https://github.com/gund/ng-dynamic-component/discussions/484)!

So if you are using this library please give your vote/feedback.

<details>
  <summary>Compatibility with Angular</summary>

| Angular     | ng-dynamic-component| NPM package                    |
| ------------| --------------------| ------------------------------ |
| >=14.1.3    | 11.x.x      | `ng-dynamic-component@^11.0.0` |
| >=14.1.3 <22| 10.3.1      | `ng-dynamic-component@^10.3.1` |
| >=14.0.0 <22| 10.2.x      | `ng-dynamic-component@^10.2.0` |
| 13.x.x      | 10.1.x      | `ng-dynamic-component@~10.1.0` |
| 12.x.x      | 9.x.x       | `ng-dynamic-component@^9.0.0`  |
| 11.x.x      | 8.x.x       | `ng-dynamic-component@^8.0.0`  |
| 10.x.x      | 7.x.x       | `ng-dynamic-component@^7.0.0`  |
| 9.x.x       | 6.x.x       | `ng-dynamic-component@^6.0.0`  |
| 8.x.x       | 5.x.x       | `ng-dynamic-component@^5.0.0`  |
| 7.x.x       | 4.x.x       | `ng-dynamic-component@^4.0.0`  |
| 6.x.x       | 3.x.x       | `ng-dynamic-component@^3.0.0`  |
| 5.x.x       | 2.x.x       | `ng-dynamic-component@^2.0.0`  |
| 4.x.x       | 1.x.x       | `ng-dynamic-component@^1.0.0`  |
| 2.x.x       | 0.x.x       | `ng-dynamic-component@^0.0.0`  |

> **Note:** Angular 22 and later require ng-dynamic-component v11 or later because Angular
> removed `ComponentFactoryResolver` and `ComponentFactory`.
</details>

## Installation

```bash
$ npm install ng-dynamic-component --save
```

## Usage

### DynamicComponent

Import `DynamicModule` where you need to render dynamic components:

```ts
import { DynamicModule } from 'ng-dynamic-component';

@NgModule({
  imports: [DynamicModule],
})
export class MyModule {}
```

Then in your component's template include `<ndc-dynamic>` where you want to render component
and bind from your component class type of component to render:

```ts
@Component({
  selector: 'my-component',
  template: ` <ndc-dynamic [ndcDynamicComponent]="component"></ndc-dynamic> `,
})
class MyComponent {
  component = Math.random() > 0.5 ? MyDynamicComponent1 : MyDynamicComponent2;
}
```

#### Standalone API

**Since v10.7.0**

You may use `<ndc-dynamic>` as a standalone component:

```ts
import { DynamicComponent } from 'ng-dynamic-component';

@Component({
  selector: 'my-component',
  template: ` <ndc-dynamic [ndcDynamicComponent]="component"></ndc-dynamic> `,
  imports: [DynamicComponent],
  standalone: true,
})
class MyComponent {
  component = Math.random() > 0.5 ? MyDynamicComponent1 : MyDynamicComponent2;
}
```

_NOTE:_ Hovewer you should be aware that this will only import `<ndc-dynamic>`
into your component and nothing else so things like dynamic inputs/outputs
will not work and you will have to import them separately (see their respective sections).

If you still need to use both `<ndc-dynamic>` and dynamic inputs/outputs it is recommended
to keep using `DynamicModule` API.

### Singal based inputs/outputs

**Since v10.8.0**

If you want to dynamically render signal based components - see [`signal-component-io`](projects/ng-dynamic-component/signal-component-io/README.md) package.

### NgComponentOutlet

You can also use [`NgComponentOutlet`](https://angular.io/api/common/NgComponentOutlet)
directive from `@angular/common` instead of `<ndc-dynamic>`.

Import `DynamicIoModule` where you need to render dynamic inputs:

```ts
import { DynamicIoModule } from 'ng-dynamic-component';

@NgModule({
  imports: [DynamicIoModule],
})
export class MyModule {}
```

Now apply `ndcDynamicInputs` and `ndcDynamicOutputs` to `ngComponentOutlet`:

```ts
@Component({
  selector: 'my-component',
  template: `<ng-template [ngComponentOutlet]="component"
                           [ndcDynamicInputs]="inputs"
                           [ndcDynamicOutputs]="outputs"
                           ></ng-template>`
})
class MyComponent {
  component = MyDynamicComponent1;
  inputs = {...};
  outputs = {...};
}
```

Also you can use `ngComponentOutlet` with `*` syntax:

```ts
@Component({
  selector: 'my-component',
  template: `<ng-container *ngComponentOutlet="component;
                            ndcDynamicInputs: inputs;
                            ndcDynamicOutputs: outputs"
                            ></ng-container>`
})
class MyComponent {
  component = MyDynamicComponent1;
  inputs = {...};
  outputs = {...};
}
```

#### Standalone API

**Since v10.7.0**

You may use dynamic inputs/outputs with `*ngComponentOutlet` as a standalone API:

```ts
import { ComponentOutletInjectorModule } from 'ng-dynamic-component';

@Component({
  selector: 'my-component',
  template: `<ng-container *ngComponentOutlet="component;
                            ndcDynamicInputs: inputs;
                            ndcDynamicOutputs: outputs"
                            ></ng-container>`
  imports: [ComponentOutletInjectorModule],
  standalone: true,
})
class MyComponent {
  component = MyDynamicComponent1;
  inputs = {...};
  outputs = {...};
}
```

If you want to use standard dynamic inputs/outputs with `ngComponentOutlet` as a standalone API
you need to add the `DynamicIoDirective` to your imports:

```ts
import { DynamicIoDirective, ComponentOutletInjectorModule } from 'ng-dynamic-component';

@Component({
  selector: 'my-component',
  template: `<ng-container *ngComponentOutlet="component;
                            ndcDynamicInputs: inputs;
                            ndcDynamicOutputs: outputs"
                            ></ng-container>`
  imports: [DynamicIoDirective, ComponentOutletInjectorModule],
  standalone: true,
})
class MyComponent {
  component = MyDynamicComponent1;
  inputs = {...};
  outputs = {...};
}
```

### Inputs and Outputs

You can pass `inputs` and `outputs` to your dynamic components:

Import module `DynamicIoModule` and then in template:

```ts
@Component({
  selector: 'my-component',
  template: `
    <ndc-dynamic
      [ndcDynamicComponent]="component"
      [ndcDynamicInputs]="inputs"
      [ndcDynamicOutputs]="outputs"
    ></ndc-dynamic>
  `,
})
class MyComponent {
  component = MyDynamicComponent1;
  inputs = {
    hello: 'world',
    something: () => 'can be really complex',
  };
  outputs = {
    onSomething: (type) => alert(type),
  };
}

@Component({
  selector: 'my-dynamic-component1',
  template: 'Dynamic Component 1',
})
class MyDynamicComponent1 {
  @Input()
  hello: string;
  @Input()
  something: Function;
  @Output()
  onSomething = new EventEmitter<string>();
}
```

Here you can update your inputs (ex. `inputs.hello = 'WORLD'`) and they will trigger standard Angular's life-cycle hooks
(of course you should consider which change detection strategy you are using).

#### Standalone API

**Since v10.7.0**

You can use standalone API to pass dynamic inputs/outputs
using `DynamicIoDirective` with `DynamicComponent` or `ngComponentOutlet`:

```ts
import { DynamicIoDirective, DynamicComponent } from 'ng-dynamic-component';

@Component({
  selector: 'my-component',
  template: `
    <ndc-dynamic
      [ndcDynamicComponent]="component"
      [ndcDynamicInputs]="inputs"
      [ndcDynamicOutputs]="outputs"
    ></ndc-dynamic>
  `,
  imports: [DynamicIoDirective, DynamicComponent]
})
class MyComponent {
  component = MyDynamicComponent1;
  inputs = {...};
  outputs = {...};
}
```

#### Output template variables

**Since v6.1.0**

When you want to provide some values to your output handlers from template -
you can do so by supplying a special object to your output that has shape `{handler: fn, args: []}`:

```ts
@Component({
  selector: 'my-component',
  template: `
    <ndc-dynamic
      [ndcDynamicComponent]="component"
      [ndcDynamicOutputs]="{
        onSomething: { handler: doSomething, args: ['$event', tplVar] }
      }"
    ></ndc-dynamic>
  `,
})
class MyComponent {
  component = MyDynamicComponent1;
  tplVar = 'some value';
  doSomething(event, tplValue) {}
}
```

Here you can specify at which argument event value should arrive via `'$event'` literal.

_HINT:_ You can override event literal by providing
[`IoEventArgumentToken`](projects/ng-dynamic-component/src/lib/io/event-argument.ts) in DI.

#### Output Handler Context

**Since v10.4.0**

You can specify the context (`this`) that will be used when calling
the output handlers by providing either:

- [`IoEventContextToken`](projects/ng-dynamic-component/src/lib/io/event-context.ts) - which will be;
  injected and used directly as a context value
- [`IoEventContextProviderToken`](projects/ng-dynamic-component/src/lib/io/event-context.ts) - which
  will be provided and instantiated within the `IoService` and used as a context value.  
  This useful if you have some generic way of retrieving a
  context for every dynamic component so you may encapsulate
  it in an Angular DI provider that will be instantiated
  within every component's injector;

Example using your component as an output context:

```ts
import { IoEventContextToken } from 'ng-dynamic-component';

@Component({
  selector: 'my-component',
  template: `
    <ndc-dynamic
      [ndcDynamicComponent]="component"
      [ndcDynamicOutputs]="{
        onSomething: doSomething
      }"
    ></ndc-dynamic>
  `,
  providers: [
    {
      provide: IoEventContextToken,
      useExisting: MyComponent,
    },
  ],
})
class MyComponent {
  component = MyDynamicComponent1;
  doSomething(event) {
    // Here `this` will be an instance of `MyComponent`
  }
}
```

### Component Creation Events

You can subscribe to component creation events, being passed a reference to the `ComponentRef`:

```ts
@Component({
  selector: 'my-component',
  template: `
    <ndc-dynamic
      [ndcDynamicComponent]="component"
      (ndcDynamicCreated)="componentCreated($event)"
    ></ndc-dynamic>
  `,
})
class MyComponent {
  component = MyDynamicComponent1;
  componentCreated(compRef: ComponentRef<any>) {
    // utilize compRef in some way ...
  }
}
```

### Attributes

**Since v2.2.0** you can now declaratively set attributes, as you would inputs, via `ndcDynamicAttributes`.

Import module `DynamicAttributesModule` and then in template:

```ts
import { AttributesMap } from 'ng-dynamic-component';

@Component({
  selector: 'my-component',
  template: `
    <ndc-dynamic
      [ndcDynamicComponent]="component"
      [ndcDynamicAttributes]="attrs"
    ></ndc-dynamic>
  `,
})
class MyComponent {
  component = MyDynamicComponent1;
  attrs: AttributesMap = {
    'my-attribute': 'attribute-value',
    class: 'some classes',
  };
}
```

Remember that attributes values are always strings (while inputs can be any value).
So to have better type safety you can use `AttributesMap` interface for your attributes maps.

Also you can use `ngComponentOutlet` and `ndcDynamicAttributes` with `*` syntax:

```ts
import { AttributesMap } from 'ng-dynamic-component';

@Component({
  selector: 'my-component',
  template: `
    <ng-container
      *ngComponentOutlet="component; ndcDynamicAttributes: attrs"
    ></ng-container>
  `,
})
class MyComponent {
  component = MyDynamicComponent1;
  attrs: AttributesMap = {
    'my-attribute': 'attribute-value',
    class: 'some classes',
  };
}
```

#### Standalone API

**Since v10.7.0**

You can use standalone API to pass dynamic inputs/outputs
using `DynamicAttributesDirective` with `DynamicComponent` or `ngComponentOutlet`:

```ts
import { DynamicAttributesDirective, DynamicComponent } from 'ng-dynamic-component';

@Component({
  selector: 'my-component',
  template: `
    <ndc-dynamic
      [ndcDynamicComponent]="component"
      [ndcDynamicAttributes]="attrs"
    ></ndc-dynamic>
  `,
  imports: [DynamicAttributesDirective, DynamicComponent]
})
class MyComponent {
  component = MyDynamicComponent1;
  attrs: AttributesMap = {...};
}
```

### Directives (experimental)

**Since v3.1.0** you can now declaratively set directives, via `ndcDynamicDirectives`.

> **NOTE**:
> There is a known issue with OnChanges hook not beign triggered on dynamic directives
> since this part of functionality has been removed from the core as Angular now
> supports this out of the box for dynamic components.
>
> In dynamic directives queries like `@ContentChild` and host decorators like `@HostBinding`
> will not work due to involved complexity required to implement it (but PRs are welcome!).

Import module `DynamicDirectivesModule` and then in template:

```ts
import { dynamicDirectiveDef } from 'ng-dynamic-component';

@Component({
  selector: 'my-component',
  template: `
    <ng-container
      [ngComponentOutlet]="component"
      [ndcDynamicDirectives]="dirs"
    ></ng-container>
  `,
})
class MyComponent {
  component = MyDynamicComponent1;
  dirs = [dynamicDirectiveDef(MyDirective)];
}
```

It's also possible to bind inputs and outputs to every dynamic directive:

```ts
import { dynamicDirectiveDef } from 'ng-dynamic-component';

@Component({
  selector: 'my-component',
  template: `
    <ng-container
      [ngComponentOutlet]="component"
      [ndcDynamicDirectives]="dirs"
    ></ng-container>
  `,
})
class MyComponent {
  component = MyDynamicComponent1;
  directiveInputs = { prop1: 'value' };
  directiveOutputs = { output1: (evt) => this.doSomeStuff(evt) };
  dirs = [
    dynamicDirectiveDef(
      MyDirective,
      this.directiveInputs,
      this.directiveOutputs,
    ),
  ];
}
```

To change inputs, just update the object:

```ts
class MyComponent {
  updateDirectiveInput() {
    this.directiveInputs.prop1 = 'new value';
  }
}
```

You can have multiple directives applied to same dynamic component (only one directive by same type):

```ts
import { dynamicDirectiveDef } from 'ng-dynamic-component';

@Component({
  selector: 'my-component',
  template: `
    <ng-container
      [ngComponentOutlet]="component"
      [ndcDynamicDirectives]="dirs"
    ></ng-container>
  `,
})
class MyComponent {
  component = MyDynamicComponent1;
  dirs = [
    dynamicDirectiveDef(MyDirective1),
    dynamicDirectiveDef(MyDirective2),
    dynamicDirectiveDef(MyDirective3),
    dynamicDirectiveDef(MyDirective1), // This will be ignored because MyDirective1 already applied above
  ];
}
```

#### Standalone API

**Since v10.7.0**

You can use standalone API to pass dynamic inputs/outputs
using `DynamicDirectivesDirective` with `DynamicComponent` or `ngComponentOutlet`:

```ts
import { DynamicDirectivesDirective, DynamicComponent } from 'ng-dynamic-component';

@Component({
  selector: 'my-component',
  template: `
    <ng-container
      [ngComponentOutlet]="component"
      [ndcDynamicDirectives]="dirs"
    ></ng-container>
  `,
  imports: [DynamicDirectivesDirective, DynamicComponent]
})
class MyComponent {
  component = MyDynamicComponent1;
  dirs = [...];
}
```

### Extra

You can have more advanced stuff over your dynamically rendered components like setting custom injector (`[ndcDynamicInjector]`)
or providing additional/overriding providers (`[ndcDynamicProviders]`) or both simultaneously
or projecting nodes (`[ndcDynamicContent]`).

**Since v10.6.0**: You can provide custom NgModuleRef (`[ndcDynamicNgModuleRef]`)
or EnvironmentInjector (`[ndcDynamicEnvironmentInjector]`) for your dynamic component.

---

NOTE: In practice functionality of this library is split in two pieces:

- one - component (`ndc-dynamic`) that is responsible for instantiating and rendering of dynamic components;
- two - directive (`ndcDynamic` also bound to `ndc-dynamic`) that is responsible for carrying inputs/outputs
  to/from dynamic component by the help of so called
  [`DynamicComponentInjector`](projects/ng-dynamic-component/src/lib/component-injector/token.ts).

Thanks to this separation you are able to connect inputs/outputs and life-cycle hooks to different mechanisms of injecting
dynamic components by implementing `DynamicComponentInjector` and providing it via
[`DynamicComponentInjectorToken`](projects/ng-dynamic-component/src/lib/component-injector/token.ts) in DI.

It was done to be able to reuse [`NgComponentOutlet`](https://github.com/angular/angular/commit/8578682) added in Angular 4-beta.3.

To see example of how to implement custom component injector - see
[`ComponentOutletInjectorDirective`](projects/ng-dynamic-component/src/lib/component-injector/component-outlet-injector.directive.ts)
that is used to integrate `NgComponentOutlet` directive with inputs/outputs.

## Contributing

You are welcome to contribute to this project.
Simply follow the [contribution guide](/CONTRIBUTING.md).

## License

MIT © [Alex Malkevich](malkevich.alex@gmail.com)

---
_Source: https://npm.io/package/ng-dynamic-component · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
