Angular Utility-Bibliothek | ng-hub-ui-utils

Angular Utility-Bibliothek mit Pipes, Fokusmanagement, Overlays, Transitions und Übersetzungs-Helfern, die von wiederverwendbaren UI-Komponenten gemeinsam genutzt werden.

Zuletzt aktualisiert 20.09.2026

Übersicht

Warum Teams nach dieser Bibliothek suchen

Nutze diese Angular Utility-Bibliothek, um die Low-Level-Bausteine hinter Overlays, Fokus-Traps, Übersetzungs-Helfern und gängigen Template-Utilities nicht neu schreiben zu müssen.

Installieren

npm install ng-hub-ui-utils

Springen zu

Ideal für

  • gemeinsame UI-Infrastruktur
  • Overlay-Systeme
  • Fokusmanagement
  • Template-Helfer

Über utils

ng-hub-ui-utils ist die gemeinsame Grundlage hinter vielen wiederverwendbaren UI-Mustern. Es ist nützlich, wenn Angular-Teams die Low-Level-Bausteine zentralisieren wollen, die Overlay-Systeme, Fokusmanagement, Pipes und Übersetzungs-Helfer projektübergreifend konsistent halten.

Funktionsleitfäden

Focus Management

Tastaturfokus innerhalb von Elementen einfangen und verwalten

Beispiele:
Fokusfalle

Den Fokus mit hubFocusTrap() innerhalb eines Modals oder Dialogs halten.

Focus Trap Demo

Click "Enable Focus Trap" and try to Tab outside the blue box. Focus will stay trapped inside.

Focus Trap Area

Status: 🔓 Free

Focusable Elements

The selector FOCUSABLE_ELEMENTS_SELECTOR finds all focusable elements.

getFocusableBoundaryElements(container)→ [first, last] elements
Fokussierbare Elemente

Die fokussierbaren Randelemente mit getFocusableBoundaryElements() abfragen.

Focus Trap Demo

Click "Enable Focus Trap" and try to Tab outside the blue box. Focus will stay trapped inside.

Focus Trap Area

Status: 🔓 Free

Focusable Elements

The selector FOCUSABLE_ELEMENTS_SELECTOR finds all focusable elements.

getFocusableBoundaryElements(container)→ [first, last] elements

Internationalisierung (i18n)

Übersetzungsservices und -Pipes für mehrsprachige Unterstützung

Beispiele:
Übersetzungsservice

HubTranslationService zur Verwaltung von Übersetzungen

TranslatePipe - Basic usage

'welcome' | translate→ Welcome to ng-hub-ui

TranslatePipe - With parameters

'greeting' | translate:{ name: 'Carlos' }→ Hello, Carlos!

TranslatePipe - Nested keys

'buttons.save' | translate→ Save
'buttons.cancel' | translate→ Cancel

Programmatic access

translationService.getTranslation('buttons.delete')→ Delete
Translate-Pipe

TranslatePipe für template-basierte Übersetzungen

TranslatePipe - Basic usage

'welcome' | translate→ Welcome to ng-hub-ui

TranslatePipe - With parameters

'greeting' | translate:{ name: 'Carlos' }→ Hello, Carlos!

TranslatePipe - Nested keys

'buttons.save' | translate→ Save
'buttons.cancel' | translate→ Cancel

Programmatic access

translationService.getTranslation('buttons.delete')→ Delete
Übersetzungs-Provider

provideHubTranslations() für die App-Konfiguration

TranslatePipe - Basic usage

'welcome' | translate→ Welcome to ng-hub-ui

TranslatePipe - With parameters

'greeting' | translate:{ name: 'Carlos' }→ Hello, Carlos!

TranslatePipe - Nested keys

'buttons.save' | translate→ Save
'buttons.cancel' | translate→ Cancel

Programmatic access

translationService.getTranslation('buttons.delete')→ Delete
Externer i18n-Adapter

Konfigurieren Sie eine reaktive Übersetzungsbrücke in app.config.ts für alle Hub-UI-Bibliotheken.

Konfigurieren Sie eine reaktive Übersetzungsbrücke in app.config.ts für alle Hub-UI-Bibliotheken.

Code
Import:
Template:
Component:

Overlay-System

Positionierte Overlays und schwebende Elemente erstellen

Beispiele:
Overlay-Service

HubOverlayService zur programmatischen Erstellung von Overlays

A connected overlay positioned below the trigger, with a backdrop that closes it on outside click.

Overlay-Referenz

OverlayRef zur Verwaltung des Overlay-Lebenszyklus

A connected overlay positioned below the trigger, with a backdrop that closes it on outside click.

Positionierung

ConnectionPositionPair für flexible Positionierung

A connected overlay positioned below the trigger, with a backdrop that closes it on outside click.

Popup-Service

Vereinfachte Popup-Verwaltung

Beispiele:
Popup-Erstellung

HubPopupService zur schnellen Popup-Erstellung

Nothing open.

Pipes

Utility-Pipes für Templates

Beispiele:
Pipes zur Typprüfung

IsStringPipe, IsObjectPipe, IsObservablePipe

GetPipe - Access nested properties

user | get:'profile.name'→ John Doe
user | get:'profile.address.city'→ New York

IsStringPipe - Type checking

'Hello' | isString→ true
123 | isString→ false

IsObjectPipe - Object detection

{ a: 1 } | isObject→ true
'string' | isObject→ false

UcfirstPipe - Capitalize first letter

'hello world' | ucfirst→ Hello world

UnwrapAsyncPipe - Observable or plain value, same template

status$ | unwrapAsync→ nothing emitted yet
'not an observable' | unwrapAsync→ not an observable
GetPipe

Auf verschachtelte Objekteigenschaften per Punktnotation zugreifen

GetPipe - Access nested properties

user | get:'profile.name'→ John Doe
user | get:'profile.address.city'→ New York

IsStringPipe - Type checking

'Hello' | isString→ true
123 | isString→ false

IsObjectPipe - Object detection

{ a: 1 } | isObject→ true
'string' | isObject→ false

UcfirstPipe - Capitalize first letter

'hello world' | ucfirst→ Hello world

UnwrapAsyncPipe - Observable or plain value, same template

status$ | unwrapAsync→ nothing emitted yet
'not an observable' | unwrapAsync→ not an observable
UcfirstPipe

Den ersten Buchstaben eines Strings großschreiben

GetPipe - Access nested properties

user | get:'profile.name'→ John Doe
user | get:'profile.address.city'→ New York

IsStringPipe - Type checking

'Hello' | isString→ true
123 | isString→ false

IsObjectPipe - Object detection

{ a: 1 } | isObject→ true
'string' | isObject→ false

UcfirstPipe - Capitalize first letter

'hello world' | ucfirst→ Hello world

UnwrapAsyncPipe - Observable or plain value, same template

status$ | unwrapAsync→ nothing emitted yet
'not an observable' | unwrapAsync→ not an observable
UnwrapAsyncPipe

Observables und Promises in Templates entpacken

GetPipe - Access nested properties

user | get:'profile.name'→ John Doe
user | get:'profile.address.city'→ New York

IsStringPipe - Type checking

'Hello' | isString→ true
123 | isString→ false

IsObjectPipe - Object detection

{ a: 1 } | isObject→ true
'string' | isObject→ false

UcfirstPipe - Capitalize first letter

'hello world' | ucfirst→ Hello world

UnwrapAsyncPipe - Observable or plain value, same template

status$ | unwrapAsync→ nothing emitted yet
'not an observable' | unwrapAsync→ not an observable

Hilfsfunktionen

Hilfsfunktionen für allgemeine Zwecke

Beispiele:
Type Guards

isString(), isNumber(), isDefined(), isPromise()

Type Guards

isString('hello')→ true
isNumber(42)→ true
isDefined(null)→ false
isDefined('value')→ true

Deep Equality

equals({a:1}, {a:1})→ true
equals([1,2], [1,2])→ true

Object Access

getValue(user, 'profile.name')→ John Doe

String Interpolation

interpolateString('Hello {{name}}', {name: 'World'})→ Hello World

String Utilities

removeAccents('Ñoño café')→ Nono cafe
padNumber(5)→ 05
String-Utilities

removeAccents(), interpolateString(), regExpEscape()

Type Guards

isString('hello')→ true
isNumber(42)→ true
isDefined(null)→ false
isDefined('value')→ true

Deep Equality

equals({a:1}, {a:1})→ true
equals([1,2], [1,2])→ true

Object Access

getValue(user, 'profile.name')→ John Doe

String Interpolation

interpolateString('Hello {{name}}', {name: 'World'})→ Hello World

String Utilities

removeAccents('Ñoño café')→ Nono cafe
padNumber(5)→ 05
Objekt-Utilities

equals() für tiefen Vergleich, getValue() für Punktnotation

Type Guards

isString('hello')→ true
isNumber(42)→ true
isDefined(null)→ false
isDefined('value')→ true

Deep Equality

equals({a:1}, {a:1})→ true
equals([1,2], [1,2])→ true

Object Access

getValue(user, 'profile.name')→ John Doe

String Interpolation

interpolateString('Hello {{name}}', {name: 'World'})→ Hello World

String Utilities

removeAccents('Ñoño café')→ Nono cafe
padNumber(5)→ 05
DOM-Utilities

closest(), reflow(), getActiveElement()

closest()

Click anywhere inside; the helper walks up to the nearest panel.

outer
inner

closest(target, '[data-panel]') → —

reflow()

Replaying an animation means removing the class and adding it back. Without a forced reflow the browser coalesces both into no change at all.

replay me
getActiveElement()

Focus either control. The second one lives inside a shadow root.

document.activeElement → —

getActiveElement() → —

runInZone()

Both streams are created with runOutsideAngular; only one is piped through the operator.

plain subscriberisInAngularZone() → —
piped through runInZone(zone)isInAngularZone() → —
ticks0
RxJS-Utilities

runInZone()-Operator für die NgZone-Integration

closest()

Click anywhere inside; the helper walks up to the nearest panel.

outer
inner

closest(target, '[data-panel]') → —

reflow()

Replaying an animation means removing the class and adding it back. Without a forced reflow the browser coalesces both into no change at all.

replay me
getActiveElement()

Focus either control. The second one lives inside a shadow root.

document.activeElement → —

getActiveElement() → —

runInZone()

Both streams are created with runOutsideAngular; only one is piped through the operator.

plain subscriberisInAngularZone() → —
piped through runInZone(zone)isInAngularZone() → —
ticks0

Scrollbar-Utilities

Scrollbar-Breite messen und kompensieren

Beispiele:
Scrollbar-Breite

Funktionen scrollbarWidth() und scrollbarPadding()

ScrollBar Service

The ScrollBar service helps manage scrollbar visibility and compensate for layout shifts when hiding scrollbars (e.g., when opening modals).

Use Case: Modal Body Lock

When opening a modal, you typically hide the body scrollbar. The ScrollBar.hide() method handles this automatically and returns a reverter function.

Status: 🔓 Normal scrolling

Code Example

import { inject } from '@angular/core';
import { ScrollBar } from 'ng-hub-ui-utils';

export class ModalService {
  private scrollBar = inject(ScrollBar);
  private revertScrollbar: (() => void) | null = null;

  openModal() {
    // Hide scrollbar and get reverter function
    this.revertScrollbar = this.scrollBar.hide();
  }

  closeModal() {
    // Restore scrollbar
    if (this.revertScrollbar) {
      this.revertScrollbar();
      this.revertScrollbar = null;
    }
  }
}

Transitions

CSS-Transition-Helfer

Beispiele:
Transition ausführen

hubRunTransition() für programmatische CSS-Transitions

transition: height 600ms · measured at 0 ms
  1. Run a transition to see when the observable completes.

Tooltip

Leichte, thematisierbare Tooltips für beliebige Elemente über die [hubTooltip]-Direktive.

Beispiele:
Tooltip-Direktive

[hubTooltip] mit hubTooltipPlacement anwenden, um beim Hover oder Fokus eine positionierte Beschriftung anzuzeigen, gestaltet über die --hub-tooltip-*-Variablen. Das ältere [tooltip] funktioniert weiterhin, ist aber veraltet: Seine schlichten Eingabenamen kollidieren mit anderen Direktiven am selben Element.

Placements (hover the buttons)
Themed with --hub-tooltip-* variables

Farbe

CSS-Farben ohne DOM parsen, messen und konvertieren

Beispiele:
Farb-Parsing

parseColor(), toHex() und isValidColor() lösen Hex, rgb(), hsl(), oklch(), oklab() und die 148 benannten Farben auf — auch beim Server-Side-Rendering

Try one:

#0b6eff
parsed
parseColor(){ r: 11, g: 110, b: 255, a: 1 }
toHex()#0b6eff
rgbToOklch(){ l: 0.58, c: 0.23, h: 260 }
isValidColor()true
toRgb()already parsed — same object back
HUB_NAMED_COLORSnot a bareword — 148 in the table
Kontrast und Lesbarkeit

contrastRatio() (WCAG 2), contrastAPCA() und readableOn(), das die zum Token --hub-sys-color-*-on passende Schriftfarbe wählt

readableOn(accent, metric)
Agrees with the design-system token on all nine
primary
#0d6efd

ink#ffffff
WCAG4.5:1
APCA-75.8
secondary
#6c757d

ink#ffffff
WCAG4.69:1
APCA-78
success
#198754

ink#ffffff
WCAG4.53:1
APCA-76.5
danger
#dc3545

ink#ffffff
WCAG4.53:1
APCA-75.4
warning
#ffc107

ink#000000
WCAG12.88:1
APCA76
info
#0dcaf0

ink#000000
WCAG10.72:1
APCA66.9
neutral
#6c757d

ink#ffffff
WCAG4.69:1
APCA-78
light
#f8f9fa

ink#000000
WCAG19.92:1
APCA102.4
dark
#212529

ink#ffffff
WCAG15.43:1
APCA-105

A highlighted border marks a chip whose ink differs from what --hub-sys-color-*-on paints in CSS.


Translucent ink has to be composited before it is measured

relativeLuminance() ignores alpha, because a translucent colour has no luminance of its own until something is behind it. Measure the ink as written and you are scoring solid black; compositeOver() blends it onto the surface first, which is what the eye is reading.

Sample text
relativeLuminance(surface)0.1833
contrastRatio(ink, surface)4.67:1
…with compositeOver(ink, surface)2.75:1
OKLCh-Konvertierungen

rgbToOklch(), oklchToRgb(), maxSrgbChroma() und clampToSrgbGamut() für Palettenarbeit in dem Raum, in dem das Designsystem mischt

red 21°
0.232
amber 85°
0.118
green 157°
0.138
cyan 218°
0.104
blue 260°
0.232
purple 320°
0.277

clampToSrgbGamut()

Asking for chroma 0.35 on the amber hue at the current lightness.

clipped per channel#d24900
chroma reduced#9a7300
in gamut as asked: false
chroma kept: 0.118
Palettenableitung

harmoniseSemantics() dreht success, warning, danger und info um höchstens 15° zum Markenton, und tintNeutrals() neigt die Grauskala genauso, mit einem Chroma-Limit von 0,015. Die Helligkeit bleibt unverändert, sodass der Kontrast erhalten bleibt, für den jede Rolle gewählt wurde.

Primary
oklch(0.55 0.17 260)
success #00866bwas #198754
warning #e7cd16was #ffc107
danger #d8336bwas #dc3545
info #44c4ffwas #0dcaf0
100
200
300
400
500
600
700
800
900

Hue rotation capped at 15°; neutral chroma capped at 0.015. Success and danger stay 173° apart.

Hauptfunktionen

Letzte Änderungen

Version 22.15.2 - 9/20/26, 12:00 AM

changed: The package manifest carries a description and a keyword list. It was the only one of the 26 with neither, while seventeen libraries depend on it, and both fields are what npm ranks a search on. Metadata only: no code, types or styles change.

Version 22.15.1 - 9/16/26, 12:00 AM

changed: Repository, issue and README links follow the move to the hub-env organization. Issues for every Hub UI package are now gathered in hub-env/hub-ui, and the repository and bugs fields of the manifest point at the new addresses. No code, types or styles change.

Version 22.15.0 - 9/8/26, 12:00 AM

added: harmoniseSemantics() and tintNeutrals(), so a brand colour derives the whole palette in one place instead of once per product. The first rotates success, warning, danger and info towards the brand's hue; the second leans the grey ramp the same way. Both leave lightness exactly where the anchor had it, because lightness is what carries the contrast each role was chosen for. Two exported numbers decide the result: HUB_MAX_HUE_SHIFT (15°), which is what keeps success and danger more than 90° apart for a reader with deuteranopia — they start 135.8° apart and a brand hue between them closes the gap by up to twice the cap — and HUB_MAX_NEUTRAL_CHROMA (0.015), which sits between the design system's own gray-500 (0.0145) and gray-600 (0.0165), so a tinted ramp is never more colourful than the grey people already accept as grey.

fixed: The DOM helpers no longer reach for globals a server render does not have. ScrollBar.hide(), hubRunTransition(), getTransitionDurationMs(), reflow(), getActiveElement() and OverlayRef each read window or document straight out of scope, which is a ReferenceError on the way to a prerendered page. They now resolve the document and the view from what they already hold — the injected DOCUMENT, the application's injector, or the element's own ownerDocument.defaultView — which also fixes the same helpers inside an iframe, where the global was the wrong document all along.

changed: reflow() returns DOMRect | null and no longer falls back to document.body, and getActiveElement() accepts null as its root. Both are announced in BREAKING_CHANGES.md; no call that passes an element changes behaviour.

Version 22.14.0 - 9/7/26, 12:00 AM

removed: TooltipDirective and its bare [tooltip] attribute, deprecated since 22.9.0. An unprefixed selector is a name in the application's namespace rather than the library's: Angular hands one attribute to every directive on the element that declares an input of that name, so nobody else could own a tooltip — not a consumer writing their own, not <hub-badge>, which declares a tooltip input and ended up drawing two, and not [hubDropdown], whose own placement is typed over eight values where a tooltip understands four. [hubTooltip] is the replacement, attribute for attribute: tooltip → hubTooltip, placement → hubTooltipPlacement, delay → hubTooltipDelay, offset → hubTooltipOffset. Breaking, and note that a template still writing tooltip="…" keeps compiling and silently shows nothing — see BREAKING_CHANGES.md.

added: A guard over the whole entry point: no directive of this package may claim a bare attribute. It reads Angular's own compiled definitions rather than a hand-kept list, so the rule covers the directive somebody adds next and not only the one just removed.

Version 22.13.0 - 9/7/26, 12:00 AM

added: OverlayPosition.origin, the element the strategy is connected to. It was known to the strategy and to nobody else, and an overlay that has to keep up with its anchor needs to be able to ask which element that is.

fixed: A floating panel stayed behind the moment its trigger moved. The overlay recomputed its position on scroll and on resize, and both of those describe the page moving under an origin that stays put. Nothing covered the opposite, the origin moving inside a page nobody scrolled and no window resized: a section collapsing above it, an image landing late, a sidebar accordion animating shut. The panel then hung at the height the trigger used to have, cut loose from the thing it belongs to, and every connected overlay in the family opens through this service, so all of them had it. The origin is now watched for as long as the panel is open and the panel is re-placed whenever its box actually changes, every frame of an animated collapse rather than once at the start of one. The box is read per frame and nothing is written unless it moved, so an overlay whose trigger sits still never touches the DOM, and the loop runs outside Angular zone so a zone-based application does not run change detection while a menu is open.

Version 22.12.1 - 9/6/26, 12:00 AM

changed: Every row of FUNCTIONALITIES.md now points at a runnable demo. Fifteen features (the popup service, the transition helpers, UnwrapAsyncPipe, the DOM and RxJS helpers and five of the colour functions) were listed as having no example, which left the unit tests as the only executable use of them. Each of those now has a demo on the documentation site, so the table reports coverage instead of a wishlist. No API changed.

fixed: The tooltip and overlay stylesheets resolve at the path the documentation gives. The manifest declared no exports map, so ng-packagr synthesised one for the published package, and a synthesised map lists only "." and "./package.json". A package that declares exports closes every subpath outside that map, so @use "ng-hub-ui-utils/styles/tooltip"; resolved to nothing even though the sheet shipped in styles/. Both sheets are now named in the manifest, extensionless and with the .scss suffix, the way every sibling package in the family already does, and ng-packagr merges those entries into the map it generates instead of replacing them.

fixed: The tooltip is announced to assistive technology and can be dismissed without a mouse. The bubble was a bare span with no id and no role, and the host was never pointed at it, so on an icon-only button, the case the tooltip is written for, a screen reader had nothing to read and the only workaround was an aria-label repeating the same text. The bubble is now role="tooltip" with an id the host is aria-describedby while it is on screen, and the attribute is put back exactly as it was found, so a description a consumer wrote is neither replaced nor left behind. The same change closes WCAG 1.4.13 for it: Escape dismisses the label without moving the pointer or the focus, and the label waits out a short grace period and stays put once the pointer lands on it, which is the only way to read one longer than its box. styles/tooltip.scss therefore ships pointer-events: auto instead of none, and the controller disables them again the moment it starts fading, so an invisible bubble never catches a click meant for what is under it. It is reached through HubTooltipController, so it arrives at all four entry points at once: [hubTooltip], the deprecated [tooltip], [hubOverflowTooltip] and hubTooltipAdapter.

Version 22.12.0 - 9/3/26, 12:00 AM

added: Colour utilities — parseColor(), toHex(), isValidColor(), relativeLuminance(), contrastRatio(), contrastAPCA(), readableOn(), compositeOver() and the OKLCh helpers rgbToOklch(), oklchToRgb(), maxSrgbChroma(), isInSrgbGamut() and clampToSrgbGamut(). The parser resolves hex (3/4/6/8 digits), rgb(), hsl(), oklch(), oklab() and the 148 CSS named colours in both modern and legacy syntax, with no DOM involved, so it runs under server-side rendering. It returns null rather than throwing on anything it cannot resolve.

added: readableOn() picks black or white by OKLCh perceptual lightness, the same decision the --hub-sys-color-*-on token computes in CSS, so a component that resolves its ink in TypeScript cannot disagree with the stylesheet. The alternative metrics are available: maximising the WCAG 2 ratio puts black text on the design system's own blue, green and red accents, which is why it is not the default.

Version 22.11.1 - 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, so the link a registry shows beside the package lands on the reference for the package the reader was already looking at. Metadata only.

Version 22.11.0 - 8/26/26, 12:00 AM

added: The overlay follows its origin. While attached it listens for scroll and resize in the capture phase and recomputes its position, coalesced into an animation frame. Before this it computed coordinates once and never again: a panel opened and then scrolled sat 122px away from the field it belonged to.

added: start and end are logical. They resolved to left and right whatever the direction, so an overlay opened from a field inside an RTL container hung off the wrong edge. The direction is read from the origin element; OverlayPosition.withDirection() overrides it.

added: OverlayRef.onKeydown(), and with it a document-level dispatcher that tells only the topmost open overlay. An overlay rarely holds focus, so a component listening on its own host never heard Escape and the panel that took over the screen could not be dismissed with the key everyone reaches for.

added: HUB_DROPDOWN_POSITIONS — the four-position fallback chain a dropdown wants, below the origin and flipping above when there is no room, expressed logically so one list serves both text directions.

fixed: Tearing an overlay down twice no longer throws. dispose() and detach() called removeChild on nodes something else may already have removed — a test teardown, a router navigation — and the DOMException took the whole destroy path with it.

Version 22.10.0 - 8/22/26, 12:00 AM

added: --hub-tooltip-white-space and --hub-tooltip-text-align, so how a label breaks and sits can be asked for per tooltip instead of through a global rule that changes every tooltip in the product. Both default to what was hard-coded, so nothing moves for anyone who says nothing.

Version 22.9.3 - 8/19/26, 12:00 AM

fixed: A tooltip whose stylesheet was never imported no longer moves the page. The element now takes position: absolute inline at creation — the same value the sheet ships — so it stops landing in normal flow at the end of the document and growing the page a scrollbar that appeared and vanished as the pointer crossed a label.

Version 22.9.2 - 8/17/26, 12:00 AM

fixed: The stylesheets are published under styles/, so @use 'ng-hub-ui-utils/styles/tooltip' names a real path instead of reaching through the package's internal folder layout.

Version 22.9.1 - 8/17/26, 12:00 AM

fixed: The published package declares its licence. An absent license field is not neutral — a registry reports it as unlicensed, which legally reads as all rights reserved. The intent was always MIT.

Version 22.9.0 - 8/17/26, 12:00 AM

added: [hubTooltip], a tooltip directive that can share an element. Its inputs are hubTooltip, hubTooltipPlacement, hubTooltipDelay and hubTooltipOffset: an attribute named for its owner cannot be claimed by anyone else, which is what the bare names could not promise next to [hubDropdown] (its own placement is typed over eight values) or <hub-badge> (which declares a tooltip input and drew two).

deprecated: TooltipDirective / [tooltip]. Kept working, unchanged — both directives are thin shells over the same HubTooltipController. Migration is attribute for attribute: tooltip → hubTooltip, placement → hubTooltipPlacement, delay → hubTooltipDelay, offset → hubTooltipOffset.

Version 22.8.1 - 8/15/26, 12:00 AM

fixed: A content-sized overlay no longer clips its own content into invisibility. Created with no intrinsic size, it computed to a 0×0 box whenever its content was absolutely positioned — which is exactly what a connected-position dropdown is — and the stylesheet's overflow: auto then hid what the overlay existed to display. An overlay created without an explicit width or height now opts out of clipping.

Version 22.8.0 - 8/14/26, 12:00 AM

added: provideHubTranslationAdapter() — the application-wide reactive bridge from an external translation service (transloco, ngx-translate, i18next…) into HubTranslationService. Register it once at bootstrap and every ng-hub-ui library picks up the host dictionary, re-emitting on every language change. Supports optional namespacing and deliberate per-label reactive overrides.

added: HUB_TRANSLATION_PREFIX — injection token that scopes the lookups of a library to a collision-safe HUBUI.<LIBRARY>.* namespace. TranslatePipe resolves the prefixed key first and falls back to the bare key, so existing flat dictionaries keep working untouched.

Version 22.7.2 - 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.7.1 - 7/27/26, 12:00 AM

fixed: --hub-overlay-zindex / --hub-overlay-backdrop-zindex actually work now: OverlayRef resolves its inline z-index through var(--hub-overlay-zindex, 1000) / var(--hub-overlay-backdrop-zindex, 999) instead of literal values, so re-stacking an overlay no longer requires !important. Defaults are unchanged.

added: OverlayConfig.zIndex — optional explicit layer for a single overlay instance; when set it takes precedence over the token.

Version 22.7.0 - 7/7/26, 12:00 AM

added: resolveHubAccent(value) — the canonical "any colour" accent resolver shared across the ng-hub-ui family: barewords map to var(--hub-sys-color-<name>, <name>), literal #hex / rgb() / oklch() / var() values pass through unchanged, empty values yield null.

Version 22.6.1 - 7/2/26, 12:00 AM

fixed: CSS variable fallbacks realigned to the ds light defaults (e.g. --hub-ref-font-family-base falls back to the system-ui stack instead of inherit); fallbacks only apply when ng-hub-ui-ds is not loaded.

Version 22.6.0 - 6/30/26, 12:00 AM

added: HubOverflowTooltipDirective ([hubOverflowTooltip]) — shows a tooltip only while the label is actually truncated, with live tracking via ResizeObserver + MutationObserver. hubOverflowTooltipMeasure splits the two questions a chip asks separately: the tooltip covers the whole control, while a CSS selector resolved inside it names the inner box whose truncation decides whether it speaks.

added: Agnostic tooltip token — HUB_TOOLTIP_ADAPTER plus provideHubTooltip(adapter) let any tooltip implementation back [hubOverflowTooltip], app-wide or per subtree; defaults to the built-in hubTooltipAdapter.

Häufig gestellte Fragen

Was ist ng-hub-ui-utils, und muss ich es installieren?

Es ist der gemeinsame Werkzeugkasten, auf dem der Rest der Familie aufbaut, und es liefert keine sichtbaren Komponenten. Siebzehn der Bibliotheken deklarieren es als erforderlichen Peer — board, modal, paginable, panels, calendar, forms und die meisten anderen —, wenn Sie also eine davon verwenden, steckt es bereits im Baum, und npm installiert Peers ab Version 7 von selbst. Es allein zu installieren ist ebenfalls in Ordnung: ng-hub-ui-ds ist sein einziger optionaler Peer.

Was steckt eigentlich in ng-hub-ui-utils?

Der native Drag-and-drop-Kern, den board, sortable und calendar teilen — moveItemInArray, transferArrayItem, resolveDropPosition und eine Pointer-Session, die Touch abdeckt —, dazu Fokus-Helfer wie hubFocusTrap und getFocusableBoundaryElements, Transition-Helfer, ein Overlay-Service mit verbundener Positionierung, ein Farb-Kit, das jede CSS-Farbe parst, nach OKLCh umrechnet und Kontrast misst, eine Tooltip-Direktive, sieben Pipes und die üblichen Type Guards und Objekt-Helfer.

Kann ich es direkt in meiner eigenen Anwendung verwenden?

Ja, und für das meiste muss nichts registriert werden: isString, HubGetPipe oder hubFocusTrap importieren und benutzen. Zwei Subsysteme brauchen allerdings Verdrahtung. HubTranslationService hat kein providedIn, also kommt provideHubTranslation() zuerst, sonst scheitert die Injection, und die Tooltip-Direktive braucht provideHubTooltip(hubTooltipAdapter). Ihre Stylesheets sind ebenfalls nicht mitgebündelt: Ergänzen Sie @use 'ng-hub-ui-utils/styles/tooltip' oder die Overlay-Entsprechung selbst.

Ist es eine Alternative zum Angular CDK?

Nein, und es versucht es gar nicht erst. Es gibt keine Portal-Abstraktion, keine Scroll-Strategien, keinen LiveAnnouncer und keinen FocusMonitor, kein Virtual Scroll und keinen Breakpoint Observer, und beim Drag and Drop sind es nur die Primitive — die Direktiven für Handle, Platzhalter und Vorschau bleiben in der jeweiligen Bibliothek, die sie braucht. Die Übersetzungsschicht ist ein Wörterbuch mit Lookup über Punktpfade und Interpolation in doppelten geschweiften Klammern: kein Plural, kein ICU, kein Lazy Loading, und ein Adapter-Token, um an eine echte i18n-Bibliothek zu delegieren. Es ist der Boden, auf dem diese Familie steht, und kein Allzweck-Toolkit.