24.0.0 (2026-08-12)
Major release: CDK Overlay dropdown, CSS-variable theming, and the multi-issue fix/enhancement set covering keyboard handling, typeahead emissions, virtual scroll measurement, disabled-state removal, SSR event replay, and non-searchable text selection.
PR: #2862 (572e5f0)
Safe ^23 line: use 23.11.0 if you do not want Overlay / these behavioral breaks.
Also includes #2848 (Overlay), #2850 (CSS-variable theming), and #2851 (224fba4).
Breaking changes
1. Dropdown panel renders in Angular CDK Overlay (#2848)
| Change | Before (≤23.6 / 23.11) | After (24.0) |
|---|---|---|
| DOM location | Panel child of <ng-select> (unless appendTo)
| CDK overlay (typically .cdk-overlay-container)
|
| CSS scoping | .my-wrapper ng-dropdown-panel { … }
| Scope via select classes: .my-select-class.ng-dropdown-panel …
|
| Peer | No CDK | @angular/cdk ^22.0.0 required
|
z-index: 1050
| Hardcoded on panel | Removed; top layer in evergreen browsers; fallback ~1000 on .cdk-overlay-container
|
appendTo
| DOM parent + positioning | DOM containment only; positioning stays viewport-based |
popover
| Opt-in | Deprecated no-op (top layer automatic) |
| Custom themes | Often set top/bottom/left on panel
| Remove positional offsets from forked themes |
pnpm add @ng-select/ng-select@24 @angular/cdkIssues addressed by Overlay: #2788, #2829, #2687, #2575, #2571, #2092.
2. Behavioral breaks
| Area | Change | Action |
|---|---|---|
| Typeahead (#1504) | Emits on typing only; select/close/clear do not emit | Use (close) / (clear)
|
| Escape (#2849) | preventDefault only when closing an open dropdown
| Parent dialogs can receive Escape when select is closed |
Issues fixed
| Issue | Problem | Fix |
|---|---|---|
| #2517 | Disabled multiselect (or disabled items) could still be removed via × / clearItem
| unselect() now no-ops when the select or item is disabled
|
| #1504 | Selecting an item (or clearing search) re-emitted on typeahead (often null)
| Typeahead emits only on typing; select / close / clear no longer call typeahead.next
|
| #1475 | Virtual scroll optionHeight used clientHeight and ignored borders
| Measure with offsetHeight so border width is included
|
| #2549 | preventDefault threw during Angular event replay (SSR/hydration)
| Skip preventDefault when $event.eventPhase === EventPhase.REPLAY
|
| #2762 | _measureDimensions wrong with custom templates + groupBy + virtual scroll
| Measure group header and option heights separately; variable item offsets in the panel service |
| #2849 | Escape always called preventDefault, even when already closed
| Only close + preventDefault when the dropdown is open; parents/dialogs can handle Escape when closed
|
| #2744 | Keyboard nav / scroll broken with typeahead + custom option heights (empty → items) | Sync panel height after items arrive; retry measurement; keep virtual window in sync after programmatic scroll |
| #2669 | Could not highlight/copy selected label when searchable=false
| Allow text selection on .ng-value; pointer-events: none on .ng-input when not searchable
|
What's changed
Behavior
- Disabled removal guard —
unselect()ignores disabled select / disabled items. - Typeahead emit contract — emits on typing only; select / close / clear reset the search input without emitting. React via
(close)/(clear)instead. Docs updated accordingly. - Escape — consumed only when it closes an open dropdown.
- Non-searchable copy — selected value text is selectable/copyable without toggling the panel.
- SSR/hydration — mousedown handler is safe under Angular event replay.
Features
- CSS-variable theming (#2850) — themes expose CSS custom properties; styling docs + demo (#2375, #2452).
Virtual scroll
- Option/group height measurement uses
offsetHeight. - Separate
itemHeight/groupHeightinNgDropdownPanelService, withgetItemHeight/getItemOffset/ variable-height range calculation. - Panel height refresh + measurement retry when items appear after an empty typeahead open.
- Re-render the virtual range when panel height sync grows
itemsPerViewport(content-sized → max-height). - Immediate virtual-range sync after keyboard-driven programmatic scroll.
Docs
- API + search example docs: typeahead emits on typing only; select / close / clear do not emit.
Notable commits (from #2851)
| Commit | Summary | Issues |
|---|---|---|
c0537b8
| Disabled unselect / remove-icon / clearItem guards
| #2517 |
1fdf433
| Typeahead emit-on-typing-only + docs | #1504 |
4cd672e
| Virtual scroll height via offsetHeight
| #1475 |
6ea28e5
| Skip preventDefault during EventPhase.REPLAY
| #2549 |
b7b9a5a
| Group vs option heights in panel service | #2762 |
efd1232
| Escape preventDefault only when open
| #2849 |
961b904
| Panel height sync for empty→items | #2744 |
25ac89b
| Copy/select selected label when not searchable | #2669 |
2884870
| Re-render virtual range after panel height sync (CI fix) | — |
Relationship to 23.7–23.11
| Version | Role |
|---|---|
| 23.7–23.10 | Mistaken Overlay / related minors — prefer deprecate; avoid for new installs |
| 23.11.0 | Safe ^23 line = 23.6 + small non-breaking fixes
|
| 24.0.0 | Correct major: Overlay + theming + full fix set |
If you already run 23.7–23.10 in production, treat 24.0.0 as the supported upgrade path and follow Breaking changes above — or pin 23.11.0 to stay pre-Overlay.