Skip to main content
Dynamic Components

Dynamic Components Overview

Estimated Time: 2 hours | Difficulty: Advanced | Prerequisites: Components, Dependency Injection
Dynamic components are created programmatically at runtime, enabling powerful patterns like modal systems, plugin architectures, and configurable UI builders. Think of it like a restaurant menu versus a food truck: normal components are menu items that exist at compile time, while dynamic components are dishes the chef invents on the fly based on what ingredients arrive. The Angular runtime creates the component, wires up dependency injection, runs lifecycle hooks, and plugs it into change detection — all happening at runtime rather than being declared in a template. When to reach for dynamic components: Modal/dialog systems, toast notifications, configurable dashboards where users choose which widgets to display, form builders driven by JSON configuration, and plugin architectures where third-party code provides components your shell did not know about at build time.

Creating Dynamic Components

Using ViewContainerRef


NgComponentOutlet

NgComponentOutlet is the declarative alternative to ViewContainerRef.createComponent(). Instead of imperatively creating components in TypeScript, you declare them in the template. This is simpler for the common case of “render component X with inputs Y” — you do not need ViewChild, AfterViewInit, or manual lifecycle management. The trade-off is less control: you cannot subscribe to outputs or get a ComponentRef for fine-grained manipulation.
When to use which: Use NgComponentOutlet for simple “swap this component” scenarios (tab content, role-based rendering). Use ViewContainerRef.createComponent() when you need to manage component lifecycle, subscribe to outputs, or create multiple instances.

The modal service pattern is the canonical use case for dynamic components. The idea: instead of littering every page component with @if (showModal) conditionals and modal markup, you create a centralized service that can open any component as a modal from anywhere in the app. The service returns a ModalRef with a result$ observable, so callers can await the user’s decision — just like window.confirm() but with rich UI. This is exactly how Angular Material’s MatDialog works internally. Building your own teaches you the mechanics and gives you full control over styling and behavior.

Component Factory with Inputs

The factory-registry pattern is essential for building configurable dashboards, CMS-driven UIs, or plugin architectures. The idea: register component types by name at startup, then create instances by name at runtime based on user configuration or backend data. This decouples “what widgets exist” from “which widgets to display” — the user (or admin) controls the layout, and the factory handles the instantiation.
Memory leak pitfall: Every createComponent() call creates a component that Angular will not destroy automatically. You must call ref.destroy() when removing a dynamic component, or call container.clear() before re-rendering. Otherwise, each render cycle adds components without removing old ones, leading to memory leaks and duplicated event handlers.

Portal Pattern (CDK)


Form Builder Pattern


Best Practices

Clean Up References

Always destroy component refs to prevent memory leaks

Use setInput()

Prefer setInput() over direct instance access for signals support

Lazy Load

Dynamically import components to reduce bundle size

Type Safety

Use generics to maintain type safety with dynamic components

Next: Custom Schematics

Learn to create custom Angular CLI schematics