@stackline/angular-multiselect-dropdown 21.1.14 → 21.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @stackline/angular-multiselect-dropdown
2
2
 
3
- > A maintained Angular multiselect dropdown for classic Angular forms workflows, with search, grouping, custom item and badge templates, lazy loading, custom CSS/SCSS theming, ADA-compliant keyboard/ARIA support, and support for both template-driven and reactive forms.
3
+ > A maintained Angular multiselect dropdown for classic Angular forms workflows, with search, grouping, custom item and badge templates, lazy loading, custom CSS/SCSS theming, accessibility-focused and keyboard/ARIA tested support, and support for both template-driven and reactive forms.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@stackline/angular-multiselect-dropdown.svg?style=flat-square)](https://www.npmjs.com/package/@stackline/angular-multiselect-dropdown)
6
6
  [![npm downloads](https://img.shields.io/npm/dt/@stackline/angular-multiselect-dropdown.svg?style=flat-square)](https://www.npmjs.com/package/@stackline/angular-multiselect-dropdown)
@@ -10,9 +10,9 @@
10
10
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue?style=flat-square&logo=typescript)](https://www.typescriptlang.org)
11
11
  [![GitHub stars](https://img.shields.io/github/stars/alexandroit/angular-multiselect-dropdown.svg?style=flat-square)](https://github.com/alexandroit/angular-multiselect-dropdown/stargazers)
12
12
 
13
- **[Documentation & Live Demos](https://alexandro.net/docs/angular/multiselect/)** | **[Angular 21 Demo](https://alexandro.net/docs/angular/multiselect/angular-21/)** | **[npm](https://www.npmjs.com/package/@stackline/angular-multiselect-dropdown)** | **[Issues](https://github.com/alexandroit/angular-multiselect-dropdown/issues)** | **[Repository](https://github.com/alexandroit/angular-multiselect-dropdown)**
13
+ **[Documentation & Live Demos](https://alexandro.net/docs/angular/multiselect/)** | **[Angular 21 Demo](https://alexandro.net/docs/angular/multiselect/angular-21/)** | **[StackBlitz Playground](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fbasic)** | **[npm](https://www.npmjs.com/package/@stackline/angular-multiselect-dropdown)** | **[Issues](https://github.com/alexandroit/angular-multiselect-dropdown/issues)** | **[Repository](https://github.com/alexandroit/angular-multiselect-dropdown)**
14
14
 
15
- **Latest tested package release:** `21.1.14` for Angular `21.x`
15
+ **Latest tested package release:** `21.2.0` for Angular `21.x`
16
16
 
17
17
  ---
18
18
 
@@ -24,9 +24,9 @@
24
24
 
25
25
  The original `angular2-multiselect-dropdown` package became difficult to keep current across multiple Angular generations. This maintained package keeps the classic API and template structure intact, introduces the new primary selector `<angular-multiselect>`, preserves the legacy alias `<angular2-multiselect>`, and publishes the project line by line so older applications can keep a predictable upgrade path.
26
26
 
27
- The repository contains the full documentation matrix from Angular 2 through Angular 21. The current package release is `21.1.14` for Angular 21.x applications.
27
+ The repository contains the full documentation matrix from Angular 2 through Angular 21. The current tested package release is `21.2.0` for Angular 21.x applications.
28
28
 
29
- The Angular 21 package is compatible with Angular 21.x and was tested in a real Angular 21.2.14 application before npm publication. The 21.1.x line adds ADA-compliant keyboard navigation, focus handling, and ARIA support for the dropdown trigger, clear-all action, selected chips, listbox, and lazy-loaded results. The 21.1.14 patch keeps that behavior, fixes responsive dropdown width handling, makes tagToBody/appendToBody use portal-style positioning so dialogs and overflow containers do not clip the open list, and keeps the open menu surface opaque.
29
+ The Angular 21 package is compatible with Angular 21.x and was tested in a real Angular 21.2.14 application before npm publication. The 21.2.0 release includes accessibility-focused keyboard navigation, focus handling, and ARIA support for the dropdown trigger, clear-all action, selected chips, listbox, and lazy-loaded results. It ports the React 19.1.x combobox contract into Angular patterns: configurable keyboard behavior, matching `aria-selected` plus `aria-checked`, selected-object preservation across async data refreshes, richer template contexts, and renderless state helpers for custom Angular HTML.
30
30
 
31
31
  ## Features
32
32
 
@@ -36,13 +36,15 @@ The Angular 21 package is compatible with Angular 21.x and was tested in a real
36
36
  | Multi-select and single-select modes | ✅ |
37
37
  | Search and filter | ✅ |
38
38
  | Group by field | ✅ |
39
- | Custom item templates (`<c-item>`) | ✅ |
39
+ | Custom item templates (`<c-item>`) with selected/ARIA context | ✅ |
40
40
  | Custom badge templates (`<c-badge>`) | ✅ |
41
+ | Renderless Angular state helper for custom HTML | ✅ |
41
42
  | Template-driven forms (`ngModel`) | ✅ |
42
43
  | Reactive forms (`formControlName`) | ✅ |
43
44
  | Lazy loading and remote-data hooks | ✅ |
44
45
  | Theming via bundled CSS/SCSS | ✅ |
45
- | ADA-compliant keyboard navigation, focus states, and ARIA labels | ✅ |
46
+ | Accessibility-focused keyboard navigation, focus states, and ARIA labels | ✅ |
47
+ | Matching `aria-selected` and `aria-checked` option state | ✅ |
46
48
  | Primary selector `<angular-multiselect>` | ✅ |
47
49
  | Legacy compatibility alias `<angular2-multiselect>` | ✅ |
48
50
  | Versioned docs builds per Angular line | ✅ |
@@ -51,18 +53,21 @@ The Angular 21 package is compatible with Angular 21.x and was tested in a real
51
53
 
52
54
  1. [Rename Note](#rename-note)
53
55
  2. [Angular Version Compatibility](#angular-version-compatibility)
54
- 3. [Installation](#installation)
55
- 4. [Setup](#setup)
56
- 5. [Custom CSS and SCSS Themes](#custom-css-and-scss-themes)
57
- 6. [Basic Usage](#basic-usage)
58
- 7. [Official Angular 21 Test Matrix](#official-angular-21-test-matrix)
59
- 8. [Custom Templates](#custom-templates)
60
- 9. [Forms Integration](#forms-integration)
61
- 10. [Lazy Loading and Remote Data](#lazy-loading-and-remote-data)
62
- 11. [Dialogs and Overflow Containers](#dialogs-and-overflow-containers)
63
- 12. [Events](#events)
64
- 13. [Run Locally](#run-locally)
65
- 14. [License](#license)
56
+ 3. [StackBlitz Playground](#stackblitz-playground)
57
+ 4. [Installation](#installation)
58
+ 5. [Setup](#setup)
59
+ 6. [Custom CSS and SCSS Themes](#custom-css-and-scss-themes)
60
+ 7. [Basic Usage](#basic-usage)
61
+ 8. [Official Angular 21 Test Matrix](#official-angular-21-test-matrix)
62
+ 9. [Keyboard and ARIA Contract](#keyboard-and-aria-contract)
63
+ 10. [Custom Templates](#custom-templates)
64
+ 11. [Renderless State Helper](#renderless-state-helper)
65
+ 12. [Forms Integration](#forms-integration)
66
+ 13. [Lazy Loading and Remote Data](#lazy-loading-and-remote-data)
67
+ 14. [Dialogs and Overflow Containers](#dialogs-and-overflow-containers)
68
+ 15. [Events](#events)
69
+ 16. [Run Locally](#run-locally)
70
+ 17. [License](#license)
66
71
 
67
72
  ## Rename Note
68
73
 
@@ -79,7 +84,7 @@ Peer ranges are intentionally bounded to the tested Angular major. The Angular 2
79
84
 
80
85
  | Package family | Framework family | Peer range | Tested release window | Demo link |
81
86
  | :---: | :---: | :---: | :---: | :--- |
82
- | **21.x** | **Angular 21 only** | **`>=21.0.0 <22.0.0`** | **21.1.14 -> 21.2.14** | [Angular 21 family docs](https://alexandro.net/docs/angular/multiselect/angular-21/) |
87
+ | **21.x** | **Angular 21 only** | **`>=21.0.0 <22.0.0`** | **21.2.0 -> 21.2.14** | [Angular 21 family docs](https://alexandro.net/docs/angular/multiselect/angular-21/) |
83
88
  | **20.x** | **Angular 20 only** | **`>=20.0.0 <21.0.0`** | **20.0.1 -> 20.3.21** | [Angular 20 family docs](https://alexandro.net/docs/angular/multiselect/angular-20/) |
84
89
  | **19.x** | **Angular 19 only** | **`>=19.0.0 <20.0.0`** | **19.0.1 -> 19.2.22** | [Angular 19 family docs](https://alexandro.net/docs/angular/multiselect/angular-19/) |
85
90
  | **18.x** | **Angular 18 only** | **`>=18.0.0 <19.0.0`** | **18.0.1 -> 18.2.14** | [Angular 18 family docs](https://alexandro.net/docs/angular/multiselect/angular-18/) |
@@ -99,13 +104,44 @@ Peer ranges are intentionally bounded to the tested Angular major. The Angular 2
99
104
  | **4.x** | **Angular 4 only** | **`>=4.0.0 <5.0.0`** | **4.0.2 -> 4.4.7** | [Angular 4 family docs](https://alexandro.net/docs/angular/multiselect/angular-4/) |
100
105
  | **2.x** | **Angular 2 only** | **`>=2.0.0 <3.0.0`** | **compatible with 2.x; tested on 2.4.10** | [Angular 2 family docs](https://alexandro.net/docs/angular/multiselect/angular-2/) |
101
106
 
107
+ ## StackBlitz Playground
108
+
109
+ The editable StackBlitz entry is one Angular 21 playground with isolated lazy routes. Official links use `stackblitz.com/github` against the maintained GitHub repository, so they stay tied to the latest pushed source instead of creating stale forked copies for every example. Each example has its own folder, Angular module, data object, and URL.
110
+
111
+ | Example | StackBlitz |
112
+ | :--- | :--- |
113
+ | Basic example | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fbasic) |
114
+ | Single selection | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fsingle-selection) |
115
+ | Search filter | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fsearch-filter) |
116
+ | Custom Search from API | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fcustom-search-api) |
117
+ | Search Filter By Property | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fsearch-filter-by-property) |
118
+ | Search and Add New Item | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fsearch-add-new-item) |
119
+ | Group By | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fgroup-by) |
120
+ | Templating | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Ftemplating) |
121
+ | Using in Forms | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Ftemplate-driven-forms) |
122
+ | Using in Reactive Forms | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Freactive-forms) |
123
+ | Virtual Scrolling | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fvirtual-scrolling) |
124
+ | Lazy Loading from API | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Flazy-loading-api) |
125
+ | Data from remote API | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fremote-data) |
126
+ | Using in List for loop | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Flist-loop) |
127
+ | Using Inside Dialog | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fdialog) |
128
+ | Multiple dropdowns | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fmultiple-dropdowns) |
129
+ | Load dynamic data | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fdynamic-data) |
130
+ | Methods | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fmethods) |
131
+ | Events | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fevents) |
132
+ | Disabled mode | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fdisabled) |
133
+ | Limit selection | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Flimit-selection) |
134
+ | Limit badges | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Flimit-badges) |
135
+ | Custom placeholder | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fcustom-placeholder) |
136
+ | Styling | [Open](https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-21?startScript=start&initialpath=%2Fstyling) |
137
+
102
138
  ## Installation
103
139
 
104
140
  ```bash
105
- npm install @stackline/angular-multiselect-dropdown@21.1.14 --save-exact
141
+ npm install @stackline/angular-multiselect-dropdown@21.2.0 --save-exact
106
142
  ```
107
143
 
108
- Install `21.1.14` for Angular 21.x applications. This line keeps the tested Angular 21 behavior, makes `<angular-multiselect>` the documented standard selector, keeps `<angular2-multiselect>` only as a legacy compatibility alias, adds the ADA-compliant keyboard/ARIA accessibility patch, fixes responsive dropdown width handling, and keeps dropdown surfaces opaque in clipped containers.
144
+ Install `21.2.0` for Angular 21.x applications. This line keeps the tested Angular 21 behavior, makes `<angular-multiselect>` the documented standard selector, keeps `<angular2-multiselect>` only as a legacy compatibility alias, adds the accessibility-focused and keyboard/ARIA tested interaction contract, fixes responsive dropdown width handling, preserves selected objects during async refreshes, and keeps dropdown surfaces opaque in clipped containers.
109
145
 
110
146
  ## Setup
111
147
 
@@ -201,7 +237,7 @@ dropdownSettings = {
201
237
 
202
238
  ## Official Angular 21 Test Matrix
203
239
 
204
- The published Angular 21 release was tested in a real Angular `21.2.14` application with `@stackline/angular-multiselect-dropdown@21.1.14`. The docs now use the same examples from that test app, including the ADA-compliant keyboard, focus, ARIA behavior, responsive dropdown width handling, opaque menu surfaces, and dialog-safe positioning added in this release line.
240
+ The published Angular 21 release was tested in a real Angular `21.2.14` application with `@stackline/angular-multiselect-dropdown@21.2.0`. The docs now use the same examples from that test app, including the accessibility-focused keyboard, focus, and ARIA behavior, responsive dropdown width handling, opaque menu surfaces, and dialog-safe positioning added in this release line.
205
241
 
206
242
  Switch between skins through the settings object:
207
243
 
@@ -236,6 +272,38 @@ The same twelve scenarios are validated for both `classic` and `material`:
236
272
  | 11 | Local lazy loading | `{ lazyLoading: true, maxHeight: 120, badgeShowLimit: 3 }` |
237
273
  | 12 | Item + chip template | `<c-badge>` and `<c-item>` custom templates |
238
274
 
275
+ ## Keyboard and ARIA Contract
276
+
277
+ The Angular line follows the same combobox contract validated in the React 19.1.x work, but exposed through Angular settings:
278
+
279
+ ```ts
280
+ dropdownSettings = {
281
+ text: 'Keyboard-tested countries',
282
+ enableSearchFilter: true,
283
+ searchAutofocus: false,
284
+ keyboard: {
285
+ space: true,
286
+ spaceOptionAction: 'toggle',
287
+ tab: true,
288
+ arrows: true,
289
+ escape: true,
290
+ backspaceRemovesLastWhenSearchEmpty: false,
291
+ deleteRemovesFocusedBadge: true
292
+ }
293
+ };
294
+ ```
295
+
296
+ Default behavior:
297
+
298
+ - Space on the trigger opens or closes the dropdown.
299
+ - Space on an option toggles that option and keeps focus on it.
300
+ - Search inputs type a normal space.
301
+ - Tab moves focus and never selects an option.
302
+ - Escape closes the list without clearing selected values.
303
+ - Empty-search Backspace does not remove selected values by default.
304
+ - Focused badge/remove buttons can remove intentionally with Backspace/Delete.
305
+ - Options expose matching `aria-selected` and `aria-checked` values.
306
+
239
307
  ## Custom Templates
240
308
 
241
309
  ```html
@@ -244,9 +312,15 @@ The same twelve scenarios are validated for both `classic` and `material`:
244
312
  [(ngModel)]="selectedItems"
245
313
  [settings]="dropdownSettings">
246
314
  <c-item>
247
- <ng-template let-item="item">
248
- <label>{{ item.itemName }}</label>
249
- <img [src]="item.image" style="width: 24px; margin-left: 8px;" />
315
+ <ng-template
316
+ let-item="item"
317
+ let-label="label"
318
+ let-selected="selected"
319
+ let-ariaChecked="ariaChecked">
320
+ <span [attr.data-aria-checked]="ariaChecked">
321
+ {{ label }}
322
+ <strong *ngIf="selected">Selected</strong>
323
+ </span>
250
324
  </ng-template>
251
325
  </c-item>
252
326
  </angular-multiselect>
@@ -254,6 +328,39 @@ The same twelve scenarios are validated for both `classic` and `material`:
254
328
 
255
329
  `<angular2-multiselect>` remains available only as a legacy compatibility alias for applications migrating from the old outdated plugin. New code and all current examples should use `<angular-multiselect>`.
256
330
 
331
+ ## Renderless State Helper
332
+
333
+ Use `AngularMultiselectState` when you want Stackline selection, filtering, item identity, object preservation, and ARIA state while owning all HTML yourself.
334
+
335
+ ```ts
336
+ import {
337
+ AngularMultiselectState,
338
+ defineAngularMultiselectSettings
339
+ } from '@stackline/angular-multiselect-dropdown';
340
+
341
+ interface CountryOption {
342
+ id: number;
343
+ itemName: string;
344
+ region: string;
345
+ }
346
+
347
+ state = new AngularMultiselectState<CountryOption>({
348
+ data: countries,
349
+ selectedItems: [countries[0]],
350
+ settings: defineAngularMultiselectSettings<CountryOption>({
351
+ primaryKey: 'id',
352
+ labelKey: 'itemName',
353
+ searchBy: ['itemName', 'region'],
354
+ ariaLabel: 'Headless country picker'
355
+ }),
356
+ onChange: (items) => {
357
+ selectedItems = items;
358
+ }
359
+ });
360
+ ```
361
+
362
+ The docs include a `Headless + ARIA` route that binds the returned trigger, listbox, and option state into fully custom Angular HTML.
363
+
257
364
  ## Forms Integration
258
365
 
259
366
  ### Template-driven forms
@@ -313,7 +420,7 @@ settings = {
313
420
  };
314
421
  ```
315
422
 
316
- In `21.1.14`, `tagToBody: true` renders the open panel outside clipping containers, keeps it aligned to the original trigger, keeps the menu surface opaque, recalculates position on scroll and resize, and cleans it up on close or destroy. `appendToBody: true` is also accepted as an alias for teams that prefer that name.
423
+ In `21.2.0`, `tagToBody: true` renders the open panel outside clipping containers, keeps it aligned to the original trigger, keeps the menu surface opaque, recalculates position on scroll and resize, and cleans it up on close or destroy. `appendToBody: true` is also accepted as an alias for teams that prefer that name.
317
424
 
318
425
  ## Events
319
426