Angular Portal and Overlay Rendering | ng-hub-ui-portal
Angular portal library for dynamic component, template and overlay rendering outside the current DOM tree with positioning control.
Last updated Sep 6, 2026
Overview
Why teams search for this library
This Angular portal library helps you render content into overlays or custom containers while keeping data flow and Angular integration predictable.
Install
npm install ng-hub-ui-portalJump to
Ideal for
- drawers
- floating panels
- overlay UIs
- dynamic containers
About portal
ng-hub-ui-portal is useful when Angular interfaces need to detach rendering from the current DOM tree: drawers, floating panels, dynamic containers or overlay-based UI. It gives teams a cleaner foundation for projected content and positioned rendering.
Feature guides
Content Rendering
Support for rendering various content types (Component, TemplateRef, String) with data injection and projection capabilities.
Examples:
Component Rendering
Open a portal with a component class and reach the instance through the returned reference.
Code
Import:
Template:
Component:
TemplateRef Rendering
Render an ng-template as portal content, with close and dismiss handed to the template context.
Code
Import:
Template:
Component:
String Content
Pass a plain string as content, for a portal that only has one thing to say.
Code
Import:
Template:
Component:
Data Passing
Hand data to the content component through a custom Injector and read the answer back from the close value.
Code
Import:
Template:
Component:
Opening Strategies
Control how portals are opened: progressive (stacked) or exclusive (toggle) modes.
Examples:
Progressive Open (Stacked)
Stack portals with open(), each one on top of the last, and ask the service how many are still up.
Code
Import:
Template:
Component:
Toggle (Exclusive)
toggle() dismisses whatever is open, waits until it is hidden, and only then shows the new portal.
Code
Import:
Template:
Component:
Container Targeting
Choose where the portal window is appended: the document body by default, or any element named by a CSS selector or handed in as an HTMLElement.
Examples:
Custom Container (Old)
Send the window to a different container and dress it with windowClass. The placement comes from the CSS of this demo — the library appends, it does not position.
Configuración de Posicionamiento
Elementos de Referencia
Targets de Portal
Configuración Actual
Code
Import:
Template:
Component:
Overlay Management
While a portal is open the page behind it stops scrolling, focus is trapped in the top-most window, and everything outside it is marked aria-hidden.
Examples:
Basic Usage (Old)
The everyday shape of the service: open a portal, wait on its result, and close it with a value.
Portal Controls
Content is rendered dynamically into the DOM (typically body) using the HubPortal service, completely detaching it from this component's DOM hierarchy while preserving Angular context.
Code
Import:
Template:
Component:
Interaction
Close/dismiss portals with results, keyboard support, and custom trigger selectors.
Examples:
Content Projection
Split the content into header, body and footer with the headerSelector and footerSelector options.
Code
Import:
Template:
Component:
Component Rendering
Open a portal with a component class and reach the instance through the returned reference.
Code
Import:
Template:
Component:
Lifecycle
Lifecycle hooks and event subscriptions for portal state management.
Examples:
Service & Injection (Old)
Portals driven from a service: toasts, dialogs and drawers, plus dismissAll, hasOpenPortals and activeInstances.
Gestión Programática de Portales
Notificaciones Toast
Modales Dinámicos
Overlays Complejos
Gestión Global
Estado del Sistema de Portales
Code
Import:
Template:
Component:
Progressive Open (Stacked)
Stack portals with open(), each one on top of the last, and ask the service how many are still up.
Code
Import:
Template:
Component:
Key features
Recent changes
Version 22.1.0 - 9/6/26, 12:00 AM
changed: Dropped the angular16 keyword from the package manifest. The peer range has required Angular 18 or newer since 22.0.1, so the keyword was advertising the package to exactly the searchers whose install it would refuse.
changed: HubPortalRef is generic, so opening a portal no longer costs you the types. HubPortal.open<C, R>() and toggle<C, R>() infer C from the class handed to them, which is what makes componentInstance the component instead of any, while R types the value that travels through close(), result and closed. Until now the README answered this with a hand-written cast that claims a type nobody checks. Both parameters default to any, but componentInstance narrows from any to C | void, so a call site that reached straight through it stops compiling: see BREAKING_CHANGES.md. content is now typed Type<C> | TemplateRef<any> | string, which is what the stack already accepted, and the whole shape mirrors what ng-hub-ui-modal settled on in 22.5.0. Dismiss reasons stay untyped on purpose, because they carry either an internal PortalDismissReasons value or whatever the consumer passed.
removed: Removed the unused BACKDROP_ATTRIBUTES constant, a commented-out import in portal-config.ts and two commented-out lines of an older toggle() implementation. None of it was reachable, and backdropClass, the option that constant named, is not part of HubPortalOptions, so leaving it in suggested a backdrop API the library does not have. No behaviour changes.
fixed: Escape now dismisses the portal, as the keyboard option has always promised. The option was declared, defaulted to true in HubPortalConfig and documented in the README and on the docs site, but no key listener existed anywhere in the library: the close button was the only way out of a focus-trapped role=dialog, which left keyboard and screen-reader users stuck and forced every consumer to wire their own listener inside the projected component. The window now rejects its result promise with PortalDismissReasons.ESC, the reason the library exported without ever emitting it, honours keyboard: false per portal, steps aside when another handler has already consumed the key, and reacts only in the window holding focus, so a stack dismisses one dialog at a time from the top.
fixed: scrollable was declared a string on the portal window while HubPortalOptions declares it a boolean. Nothing misbehaved, because the template only tests the input for truthiness and the option reaches it through the name-based setInput, which no compiler ever checks, so the two had been free to disagree since the input was written. They now agree, which is what stops the next reader from believing the window and passing a string.
deprecated: HubPortalModule is deprecated and will be removed in 23.0.0. Its whole body is providers: [HubPortal], and HubPortal is providedIn: root, so importing the module never enabled the service; it only added a redundant second instance in whichever injector declared the import, delegating to the same root HubPortalStack and HubPortalConfig. Inject HubPortal and drop the import. The class carried no @deprecated tag until now, so neither an editor nor the build could warn anyone it was on its way out. See BREAKING_CHANGES.md.
Version 22.0.5 - 9/1/26, 12:00 AM
changed: The homepage in the manifest points at this library's own documentation page rather than at the site root. It is the link a registry shows beside the package and the one a reader clicks from it, and landing on a front page they then have to search is a worse answer than landing on the reference for the package they were already looking at. Metadata only — no code, no types, no styles change, and nothing a consumer imports is affected.
Version 22.0.4 - 8/8/26, 12:00 AM
fixed: Documentation links now point at the canonical localized URLs. The README linked to https://hubui.dev/<path> with no locale prefix and no trailing slash, and both forms are 301-redirected, so every reader arriving from npm or GitHub landed on a redirect instead of the canonical page.
Version 22.0.3 - 7/28/26, 12:00 AM
fixed: Removed the invalid aria-portal attribute from the portal window host (not a real ARIA attribute); role=dialog and the aria-labelledby/describedby wiring stay.
Version 22.0.2 - 7/26/26, 12:00 AM
fixed: Declared the real ng-hub-ui-utils peer range (>=22.0.0); the previous >=1.0.0 floor allowed resolving an incompatible utils major.
Version 22.0.1 - 6/26/26, 12:00 AM
fixed: Corrected the Angular peer dependency range to >=18.0.0. The library uses APIs introduced in Angular 17 (signal input()/output(), the @if control flow and signal queries), so the previous >=16.0.0 range let it install on versions it cannot run on.
fixed: Corrected the ng-hub-ui-utils peer range. The previous caret range resolved to >=1 <2, which excluded the current utils (22.x) and made the peer impossible to satisfy.
Version 22.0.0 - 6/17/26, 12:00 AM
changed: Aligned with Angular 22.
changed: README documentation standardized.
Version 0.3.4 - 6/14/26, 12:00 AM
fixed: Portal window options (animation, windowClass, portalDialogClass, …) are applied through ComponentRef.setInput instead of being assigned onto the instance. Since HubPortalWindow declares them as signal inputs, the direct assignment replaced the read-only signal function and threw TypeError: ctx.animation is not a function on every open().
fixed: Guarded parentNode when removing the window element during teardown, which threw when the element had already been detached.