<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alexandro Paixao Marques</title>
    <description>The latest articles on DEV Community by Alexandro Paixao Marques (@alexandro_net).</description>
    <link>https://dev.to/alexandro_net</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3951163%2Fdc3b2f72-155a-49ac-bddb-3679f4b92c6a.png</url>
      <title>DEV Community: Alexandro Paixao Marques</title>
      <link>https://dev.to/alexandro_net</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alexandro_net"/>
    <language>en</language>
    <item>
      <title>React Multiselect Dropdown 19: controlled state, skins, modals, and accessibility</title>
      <dc:creator>Alexandro Paixao Marques</dc:creator>
      <pubDate>Sat, 30 May 2026 17:30:21 +0000</pubDate>
      <link>https://dev.to/alexandro_net/react-multiselect-dropdown-19-controlled-state-skins-modals-and-accessibility-5j5</link>
      <guid>https://dev.to/alexandro_net/react-multiselect-dropdown-19-controlled-state-skins-modals-and-accessibility-5j5</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkd397b7jo2yxumcs2zfq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkd397b7jo2yxumcs2zfq.gif" alt=" " width="400" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Modern React applications rarely need just a dropdown.&lt;/p&gt;

&lt;p&gt;In real projects, a multiselect dropdown usually sits inside something more important: filters, dashboards, reporting tools, permission editors, workflow screens, admin panels, and data-heavy forms where users need to search, group, select, clear, validate, and keep state consistent. It is almost never the feature. It is the control that everything else in the form depends on.&lt;/p&gt;

&lt;p&gt;That is the context behind &lt;strong&gt;Stackline React Multiselect Dropdown&lt;/strong&gt;, maintained for &lt;strong&gt;React 19&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is the React counterpart to the Stackline Angular line, and it is meant to behave like one. The two packages share the same combobox and ARIA contract, the same skin system, the same headless philosophy, the same per-major versioning, and the same live-example model. If your organization runs both Angular and React, the goal is that a multiselect feels and behaves the same way in both stacks, instead of being two unrelated controls that happen to share a name. In fact, the combobox contract was first defined and validated in this React line, then carried into the Angular line — so on the React side you are looking at the reference implementation.&lt;/p&gt;

&lt;p&gt;React 19 is a good target for that. It is the version where React moved decisively toward explicit async state and less boilerplate: Actions and the new form hooks, the &lt;code&gt;use&lt;/code&gt; hook for reading promises and context during render, &lt;code&gt;ref&lt;/code&gt; as a plain prop instead of &lt;code&gt;forwardRef&lt;/code&gt;, React Server Components as a production pattern, and the React Compiler taking over manual memoization. A maintained, accessibility-focused selection component should slot cleanly into that world without fighting it.&lt;/p&gt;

&lt;p&gt;This release of the library is not just about making a dropdown render on the latest React. The goal is a practical component that can be adopted in real applications, exercised through live examples, and customized at whatever depth a team needs — from a drop-in styled component to a fully headless hook where the application owns every element and every line of CSS.&lt;/p&gt;

&lt;p&gt;Install the React 19 line with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @stackline/react-multiselect-dropdown
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Links:&lt;/p&gt;

&lt;p&gt;npm:&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/@stackline/react-multiselect-dropdown" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@stackline/react-multiselect-dropdown&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Documentation (React 19):&lt;br&gt;
&lt;a href="https://alexandro.net/docs/react/multiselect/react-19/#/basic" rel="noopener noreferrer"&gt;https://alexandro.net/docs/react/multiselect/react-19/#/basic&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Live demo / interactive playground (StackBlitz):&lt;br&gt;
&lt;a href="https://stackblitz.com/github/alexandroit/stackline-react-multiselect-react-19?file=src%2Fexamples%2Fbasic%2Fbasic.component.tsx&amp;amp;startScript=start&amp;amp;initialpath=%2Fbasic" rel="noopener noreferrer"&gt;https://stackblitz.com/github/alexandroit/stackline-react-multiselect-react-19?file=src%2Fexamples%2Fbasic%2Fbasic.component.tsx&amp;amp;startScript=start&amp;amp;initialpath=%2Fbasic&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub:&lt;br&gt;
&lt;a href="https://github.com/alexandroit/react-multiselect-dropdown" rel="noopener noreferrer"&gt;https://github.com/alexandroit/react-multiselect-dropdown&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For new releases, documentation updates, and the Angular counterpart, visit:&lt;br&gt;
&lt;a href="https://alexandro.net" rel="noopener noreferrer"&gt;https://alexandro.net&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What the library provides
&lt;/h2&gt;

&lt;p&gt;Stackline React Multiselect Dropdown is a React multiselect component designed for real application forms, dashboards, filters, and enterprise interfaces.&lt;/p&gt;

&lt;p&gt;It supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;single-select and multi-select modes&lt;/li&gt;
&lt;li&gt;controlled and uncontrolled selection&lt;/li&gt;
&lt;li&gt;search and filtering&lt;/li&gt;
&lt;li&gt;select all and clear all behavior&lt;/li&gt;
&lt;li&gt;grouped options&lt;/li&gt;
&lt;li&gt;custom item and badge render functions&lt;/li&gt;
&lt;li&gt;a guided Slots API for replacing component structure without losing behavior&lt;/li&gt;
&lt;li&gt;headless hooks (&lt;code&gt;useMultiSelectDropdown&lt;/code&gt;, &lt;code&gt;useMultiSelectState&lt;/code&gt;) for fully custom interfaces&lt;/li&gt;
&lt;li&gt;a type-safe factory (&lt;code&gt;createMultiSelectDropdown&amp;lt;T&amp;gt;()&lt;/code&gt;) to bind the item type once&lt;/li&gt;
&lt;li&gt;imperative &lt;code&gt;ref&lt;/code&gt; methods (open, close, focus, select all, clear)&lt;/li&gt;
&lt;li&gt;lazy loading hooks and dynamic data&lt;/li&gt;
&lt;li&gt;five built-in skins (&lt;code&gt;classic&lt;/code&gt;, &lt;code&gt;material&lt;/code&gt;, &lt;code&gt;dark&lt;/code&gt;, &lt;code&gt;custom&lt;/code&gt;, &lt;code&gt;brand&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;accessibility-focused keyboard navigation, focus handling, and a documented combobox/ARIA contract&lt;/li&gt;
&lt;li&gt;body-overlay positioning for dialogs and clipped containers&lt;/li&gt;
&lt;li&gt;versioned documentation per React major&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A multiselect component can look simple from the outside, but once it is used across several forms and workflows, replacing it becomes expensive. It affects state shape, validation, events, styling, selected state, reset behavior, focus and keyboard behavior, and sometimes even backend query logic. The cost is rarely in the first screen. It is in the twentieth screen that quietly depends on the behavior of the first.&lt;/p&gt;

&lt;p&gt;That is why a predictable API, accessibility, customization depth, and a clear versioning story matter more than a long feature list.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why this package exists
&lt;/h2&gt;

&lt;p&gt;There are many dropdowns and select components available for React, but the hard part in real applications is rarely the first implementation.&lt;/p&gt;

&lt;p&gt;The hard part is keeping the component stable while React moves forward, while forms evolve, while UI layouts become more complex, while accessibility gets audited, and while a design system needs to take over rendering without rebuilding selection logic from scratch.&lt;/p&gt;

&lt;p&gt;React 19 makes that especially relevant. The framework is pushing toward Server Components, form Actions, and the React Compiler, which changes how data arrives and how much manual wiring a component needs. A selection control should be able to live inside that world: take its data from a Server Component or an Action, run as a client component for the parts that genuinely need the browser, and stay out of the way of the compiler.&lt;/p&gt;

&lt;p&gt;This package focuses on a practical set of goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep React 19 compatibility clear and validated, not optimistic&lt;/li&gt;
&lt;li&gt;keep a controlled, predictable API: &lt;code&gt;data&lt;/code&gt; in, &lt;code&gt;selectedItems&lt;/code&gt; bound, updates through &lt;code&gt;onChange&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;offer escalating layers of control, so a team only owns as much markup as it actually needs&lt;/li&gt;
&lt;li&gt;ship a documented keyboard and ARIA contract instead of leaving accessibility as an afterthought&lt;/li&gt;
&lt;li&gt;provide working examples that can be tested in the browser before installing&lt;/li&gt;
&lt;li&gt;keep the same behavior contract as the Angular line, so multi-stack teams get consistency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The intention is not to reinvent how selection works. The intention is to make a commonly needed UI component easy to adopt at any level of customization, and to keep it behaving the same way across React versions and across the Angular counterpart.&lt;/p&gt;
&lt;h2&gt;
  
  
  React 19 in context
&lt;/h2&gt;

&lt;p&gt;It helps to be explicit about what React 19 changes, because it shapes how any selection component should behave in a 2026 codebase.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;Before React 19&lt;/th&gt;
&lt;th&gt;React 19&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Async/form state&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;useState&lt;/code&gt; + &lt;code&gt;useTransition&lt;/code&gt; + manual pending/error handling&lt;/td&gt;
&lt;td&gt;Actions, with &lt;code&gt;useActionState&lt;/code&gt;, &lt;code&gt;useFormStatus&lt;/code&gt;, and &lt;code&gt;useOptimistic&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reading async data and context&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;useEffect&lt;/code&gt; + state; context only via &lt;code&gt;useContext&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;use()&lt;/code&gt; reads promises and context during render, and can be called conditionally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Refs on function components&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;forwardRef&lt;/code&gt; wrapper&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ref&lt;/code&gt; as a regular prop; &lt;code&gt;forwardRef&lt;/code&gt; no longer required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server rendering&lt;/td&gt;
&lt;td&gt;SSR only&lt;/td&gt;
&lt;td&gt;React Server Components as a production pattern, with a &lt;code&gt;"use client"&lt;/code&gt; boundary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memoization&lt;/td&gt;
&lt;td&gt;manual &lt;code&gt;useMemo&lt;/code&gt; / &lt;code&gt;useCallback&lt;/code&gt; / &lt;code&gt;memo&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;React Compiler inserts memoization automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Document head&lt;/td&gt;
&lt;td&gt;third-party helmet libraries&lt;/td&gt;
&lt;td&gt;native metadata hoisting for &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Types&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@types/react@18&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@types/react@19&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There is a clear parallel with where Angular went in the same period. Angular's "signal-first" direction (signals, zoneless change detection, Signal Forms) and React's Actions, &lt;code&gt;use()&lt;/code&gt;, and Compiler are different mechanisms aiming at the same outcome: more explicit reactivity, less boilerplate, and rendering that is easier to reason about. That convergence is exactly why a single shared behavior contract across both stacks is worth maintaining.&lt;/p&gt;

&lt;p&gt;Where does a styled, controlled multiselect fit in React 19? It is, by nature, a client component. Selection, keyboard handling, focus management, and ARIA state all need the browser, so the component runs under &lt;code&gt;"use client"&lt;/code&gt;, and that is correct rather than a limitation. The boundary stays clean: a Server Component or an Action can fetch the option list, and the multiselect owns the interaction. For teams that want to push further — fit an RSC-driven design system, drop the bundled CSS, or own every element — the headless hooks provide the selection, filtering, grouping, and ARIA logic without any DOM or CSS, which is the React equivalent of a renderless control.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;For React 19 projects, install the validated &lt;code&gt;19.x&lt;/code&gt; line with an exact version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @stackline/react-multiselect-dropdown@19.1.1 &lt;span class="nt"&gt;--save-exact&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pinning with &lt;code&gt;--save-exact&lt;/code&gt; keeps compatibility predictable across local environments, CI pipelines, and production builds. The styled component ships its own styles and injects them at runtime; the headless hooks inject no CSS and let your application own the markup and styling.&lt;/p&gt;

&lt;p&gt;Unlike the Angular 22 line, which deliberately loosens its peer range to be install-ready for the next framework major, the React 19 line keeps a strict peer range of &lt;code&gt;&amp;gt;=19.0.0 &amp;lt;20.0.0&lt;/code&gt;. React's release cadence is slower and less calendar-driven than Angular's, so there is no fixed next-major date to prepare for; bounding the package to the tested React major is the more honest default here. The package was validated against React &lt;code&gt;19.2.4&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;There is no module to register. React setup is three small steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Import the component
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MultiSelectDropdown&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stackline/react-multiselect-dropdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;DropdownSettings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;MultiSelectDropdownHandle&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stackline/react-multiselect-dropdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Keep selection in React state
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectedCountries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelectedCountries&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Pass a stable settings object
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DropdownSettings&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Country&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Select countries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;enableSearchFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;labelKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itemName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;badgeShowLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;skin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;classic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wrapping the settings object in &lt;code&gt;useMemo&lt;/code&gt; keeps its identity stable across renders, which avoids unnecessary work in the component. This is the React analogue of the Angular line's single settings object: most behavior is configured in one place rather than spread across props.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic usage
&lt;/h2&gt;

&lt;p&gt;A typical implementation starts with a list of items, selected state, and a settings object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;MultiSelectDropdown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DropdownSettings&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stackline/react-multiselect-dropdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Country&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;itemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;countries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;itemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Brazil&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Brasilia&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;South America&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;itemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Canada&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ottawa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;North America&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;itemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Portugal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lisbon&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Europe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;itemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;United States&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Washington, DC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;North America&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;itemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Argentina&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Buenos Aires&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;South America&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;itemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mexico&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mexico City&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;North America&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;CountrySelector&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectedCountries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelectedCountries&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;countries&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DropdownSettings&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Country&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;singleSelection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Select countries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;selectAllText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Select all&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;unSelectAllText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Clear all&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;enableSearchFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;searchPlaceholderText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;labelKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itemName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;badgeShowLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;maxHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;260&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;showCheckbox&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;noDataLabel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;skin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;classic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;appendToBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MultiSelectDropdown&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;countries&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;selectedItems&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selectedCountries&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setSelectedCountries&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onSelect&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;selected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onDeSelect&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;removed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onSelectAll&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;selected all&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onDeSelectAll&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cleared all&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The controlled contract is the core idea: you hold the selected array, the component renders from it, and every change comes back through &lt;code&gt;onChange&lt;/code&gt;. Note the &lt;code&gt;skin&lt;/code&gt; key: the React line selects styling through &lt;code&gt;skin&lt;/code&gt;. The older &lt;code&gt;theme&lt;/code&gt; key still works as a legacy alias, but new code should use &lt;code&gt;skin&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Customization paths
&lt;/h2&gt;

&lt;p&gt;This is the part where React idioms shine, and it is the React equivalent of "use the right amount of control." Instead of one component with escape hatches, the package exposes escalating layers so a team owns only as much markup as it actually needs.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;What you own&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;MultiSelectDropdown /&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fast forms, filters, dashboards, admin screens&lt;/td&gt;
&lt;td&gt;Data, selected state, settings, events, optional render functions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;createMultiSelectDropdown&amp;lt;T&amp;gt;()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Binding the item type once for a feature or design-system wrapper&lt;/td&gt;
&lt;td&gt;A typed component family, typed settings, typed slots, typed hooks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;slots&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Custom HTML around proven component behavior&lt;/td&gt;
&lt;td&gt;Specific DOM pieces (trigger, badges, menu, search, groups, options, footer)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;useMultiSelectDropdown&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fully custom interfaces and design systems&lt;/td&gt;
&lt;td&gt;All markup and CSS, while the package provides state, ARIA prop getters, keyboard flow, grouping, callbacks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;useMultiSelectState&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Advanced state engines or an existing combobox shell&lt;/td&gt;
&lt;td&gt;Every element, every event binding, all visual behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For most teams, start with the component. Reach for &lt;code&gt;slots&lt;/code&gt; when the component works but your layout needs a different shell. Reach for the headless hooks when the application must own the whole combobox contract. The important point is that selection, filtering, keyboard, focus, ARIA, body-overlay positioning, and async behavior stay handled by the package no matter which layer you choose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type-safe factory
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;createMultiSelectDropdown&amp;lt;T&amp;gt;()&lt;/code&gt; when a feature, package, or design-system wrapper should bind the item type once and reuse it across the component, settings, slots, and hooks. This is optional; the plain &lt;code&gt;&amp;lt;MultiSelectDropdown /&amp;gt;&lt;/code&gt; API remains the fastest path for most screens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createMultiSelectDropdown&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stackline/react-multiselect-dropdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Country&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;itemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CountryMultiselect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createMultiSelectDropdown&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Country&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;countrySettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CountryMultiselect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineSettings&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Choose countries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;labelKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itemName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;searchBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itemName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;capital&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;groupBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;region&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;enableSearchFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;badgeShowLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;countrySlots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CountryMultiselect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineSlots&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;checkbox&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;checkbox&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;small&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;capital&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; - &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;small&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;CountryFilter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;countries&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;countries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectedCountries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelectedCountries&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CountryMultiselect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Dropdown&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;countries&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;selectedItems&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selectedCountries&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setSelectedCountries&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;countrySettings&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;slots&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;countrySlots&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the factory, &lt;code&gt;primaryKey&lt;/code&gt;, &lt;code&gt;labelKey&lt;/code&gt;, &lt;code&gt;searchBy&lt;/code&gt;, and &lt;code&gt;groupBy&lt;/code&gt; are checked against &lt;code&gt;keyof Country&lt;/code&gt;. Typos such as &lt;code&gt;labelKey: 'itemname'&lt;/code&gt; or &lt;code&gt;searchBy: ['city']&lt;/code&gt; fail at compile time instead of silently producing an empty search.&lt;/p&gt;

&lt;h2&gt;
  
  
  Settings-driven behavior
&lt;/h2&gt;

&lt;p&gt;Most behavior is configured through the settings object instead of a long list of props.&lt;/p&gt;

&lt;p&gt;Common settings include &lt;code&gt;singleSelection&lt;/code&gt;, &lt;code&gt;enableSearchFilter&lt;/code&gt;, &lt;code&gt;searchBy&lt;/code&gt;, &lt;code&gt;searchPlaceholderText&lt;/code&gt;, &lt;code&gt;maxHeight&lt;/code&gt;, &lt;code&gt;badgeShowLimit&lt;/code&gt;, &lt;code&gt;limitSelection&lt;/code&gt;, &lt;code&gt;disabled&lt;/code&gt;, &lt;code&gt;groupBy&lt;/code&gt;, &lt;code&gt;selectGroup&lt;/code&gt;, &lt;code&gt;showCheckbox&lt;/code&gt;, &lt;code&gt;noDataLabel&lt;/code&gt;, &lt;code&gt;lazyLoading&lt;/code&gt;, &lt;code&gt;labelKey&lt;/code&gt;, &lt;code&gt;primaryKey&lt;/code&gt;, &lt;code&gt;addNewItemOnFilter&lt;/code&gt;, &lt;code&gt;clearAll&lt;/code&gt;, &lt;code&gt;keyboard&lt;/code&gt;, &lt;code&gt;autoPosition&lt;/code&gt;, &lt;code&gt;position&lt;/code&gt;, &lt;code&gt;skin&lt;/code&gt; (legacy alias: &lt;code&gt;theme&lt;/code&gt;), &lt;code&gt;appendToBody&lt;/code&gt;, and &lt;code&gt;tagToBody&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Single selection without checkboxes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DropdownSettings&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Country&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;singleSelection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;showCheckbox&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;enableCheckAll&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Select one country&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Selection limit
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DropdownSettings&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Country&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;singleSelection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;limitSelection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;badgeShowLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Select up to 2 countries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Grouped data
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DropdownSettings&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Country&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;groupBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;region&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;selectGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;enableSearchFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Select countries by region&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A single settings object is easy to standardize and share across an application. The most common cause of "the dropdown behaves slightly differently on this screen" is ten slightly different settings objects scattered across ten components; one shared object removes that drift.&lt;/p&gt;

&lt;h2&gt;
  
  
  Search and filtering
&lt;/h2&gt;

&lt;p&gt;Search becomes important as soon as datasets grow.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;enableSearchFilter&lt;/code&gt; turns search on, and &lt;code&gt;searchBy&lt;/code&gt; restricts filtering to specific fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DropdownSettings&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Country&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;enableSearchFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;searchPlaceholderText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Search countries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;searchBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itemName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;capital&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives two useful modes: broad search across item properties, or controlled search over selected fields. Controlled search matters when items carry internal IDs, flags, or hidden metadata that should not match user input — a user typing "12" should not silently match an internal &lt;code&gt;id&lt;/code&gt; of &lt;code&gt;12&lt;/code&gt; unless you decided that on purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keyboard and accessibility — the combobox contract
&lt;/h2&gt;

&lt;p&gt;This is the part of the React line that deserves the most attention, and it is the reference contract that the Angular line adopted.&lt;/p&gt;

&lt;p&gt;Accessibility in a multiselect is a behavior contract, not a single attribute: what the keyboard does on the trigger versus inside the list, how focus moves after a selection, how selected chips are announced, and what screen readers report for each option. Version &lt;code&gt;19.1.1&lt;/code&gt; tightens the details that usually break first in production forms.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;th&gt;Contract&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Focus after selection or removal&lt;/td&gt;
&lt;td&gt;Focus returns to search while the list stays open, or to the trigger when the list closes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Option selection state&lt;/td&gt;
&lt;td&gt;Options expose matching &lt;code&gt;aria-selected&lt;/code&gt; and &lt;code&gt;aria-checked&lt;/code&gt; values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backspace in search&lt;/td&gt;
&lt;td&gt;Edits the query; with an empty query it does not remove selected values by default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backspace/Delete on a focused badge remove button&lt;/td&gt;
&lt;td&gt;Removes that selected badge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Escape&lt;/td&gt;
&lt;td&gt;Closes the list without clearing selected values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Async add-item&lt;/td&gt;
&lt;td&gt;Late async responses are ignored when a newer add request has already resolved&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Async option refresh&lt;/td&gt;
&lt;td&gt;Selected objects are merged back into the option source, so values are not lost when data refreshes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keyboard navigation&lt;/td&gt;
&lt;td&gt;Trigger ArrowDown/ArrowUp, option Home/End, and stable option ids keep focus and ARIA predictable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Keyboard behavior is enabled by default and configurable through &lt;code&gt;settings.keyboard&lt;/code&gt; when an application needs a stricter model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DropdownSettings&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Country&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Countries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;enableSearchFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;keyboard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;spaceOptionAction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toggle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;arrows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;backspaceRemovesLastWhenSearchEmpty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;deleteRemovesFocusedBadge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set any key to &lt;code&gt;false&lt;/code&gt; to disable that behavior. &lt;code&gt;backspaceRemovesLastWhenSearchEmpty&lt;/code&gt; can be turned on for apps that want the legacy "empty search removes last badge" pattern (&lt;code&gt;keyboard.backspace&lt;/code&gt; is still accepted as a deprecated alias). &lt;code&gt;spaceOptionAction&lt;/code&gt; controls focused options: &lt;code&gt;'toggle'&lt;/code&gt; keeps focus on the current option, while &lt;code&gt;'toggle-and-next'&lt;/code&gt; toggles and advances to the next enabled option. &lt;code&gt;escapeToClose: false&lt;/code&gt; is still supported and also disables &lt;code&gt;keyboard.escape&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The edge cases that usually break accessibility — space inside search, tab stealing a selection, escape wiping a form field, a remote refresh dropping the user's selection — were handled deliberately. Because this is the same contract the Angular line follows, the keyboard and screen-reader behavior matches across both stacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom rendering and the Slots API
&lt;/h2&gt;

&lt;p&gt;There are two levels of visual customization, and they map cleanly to two needs.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;renderItem&lt;/code&gt; and &lt;code&gt;renderBadge&lt;/code&gt; when you only need to replace the inner content of an option row or a selected chip:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MultiSelectDropdown&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;countries&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;selectedItems&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selectedCountries&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setSelectedCountries&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;renderItem&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;small&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;capital&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;small&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;renderBadge&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the Slots API when you need to replace component structure — the trigger, menu, search shell, option row, badge, footer, and more. The rule is simple: spread the supplied &lt;code&gt;props&lt;/code&gt; onto the element that plays that role. Those props carry the required refs, ARIA attributes, keyboard handlers, click handlers, ids, classes, and positioning styles, so you change the markup without losing the tested behavior.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;MultiSelectDropdown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MultiSelectDropdownSlots&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stackline/react-multiselect-dropdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;countrySlots&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MultiSelectDropdownSlots&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Country&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;Trigger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; country-trigger`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectedItems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectedItems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; selected`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Choose countries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;Badge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;removeButton&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; country-badge`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;removeButton&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;checkbox&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; country-option`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;checkbox&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;small&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;capital&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; - &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;small&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;MenuFooter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filteredItems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; visible options&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full set of slots covers &lt;code&gt;Root&lt;/code&gt;, &lt;code&gt;Trigger&lt;/code&gt;, &lt;code&gt;Value&lt;/code&gt;, &lt;code&gt;Placeholder&lt;/code&gt;, &lt;code&gt;SingleValue&lt;/code&gt;, &lt;code&gt;BadgeList&lt;/code&gt;, &lt;code&gt;Badge&lt;/code&gt;, &lt;code&gt;BadgeLabel&lt;/code&gt;, &lt;code&gt;BadgeRemove&lt;/code&gt;, &lt;code&gt;Actions&lt;/code&gt;, &lt;code&gt;OverflowCounter&lt;/code&gt;, &lt;code&gt;ClearAll&lt;/code&gt;, &lt;code&gt;Arrow&lt;/code&gt;, &lt;code&gt;Menu&lt;/code&gt;, &lt;code&gt;Toolbar&lt;/code&gt;, &lt;code&gt;BulkActions&lt;/code&gt;, &lt;code&gt;SelectAll&lt;/code&gt;, &lt;code&gt;AddNewItem&lt;/code&gt;, &lt;code&gt;Search&lt;/code&gt;, &lt;code&gt;OptionList&lt;/code&gt;, &lt;code&gt;Group&lt;/code&gt;, &lt;code&gt;GroupHeader&lt;/code&gt;, &lt;code&gt;GroupAction&lt;/code&gt;, &lt;code&gt;Option&lt;/code&gt;, &lt;code&gt;Checkbox&lt;/code&gt;, &lt;code&gt;LoadingState&lt;/code&gt;, &lt;code&gt;EmptyState&lt;/code&gt;, and &lt;code&gt;MenuFooter&lt;/code&gt;. This is the React parallel to the Angular line's custom item and badge templates, taken further: in React you can replace almost any structural piece, not just the option and chip.&lt;/p&gt;

&lt;h2&gt;
  
  
  Headless usage
&lt;/h2&gt;

&lt;p&gt;For the cases where slots are not enough, the package ships headless hooks. This is the React equivalent of the Angular renderless state helper: you write all of the HTML and CSS, and the package gives you state, ARIA prop getters, keyboard flow, grouping, limits, and callbacks.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;useMultiSelectDropdown&lt;/code&gt; returns prop getters and state for a fully custom interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useMultiSelectDropdown&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stackline/react-multiselect-dropdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;HeadlessCountries&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectedItems&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelectedItems&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;countries&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dropdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMultiSelectDropdown&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;countries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;selectedItems&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;setSelectedItems&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Choose countries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;enableSearchFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;searchPlaceholderText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Search country&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;groupBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;region&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;labelKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itemName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;badgeShowLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;clearAll&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"country-picker"&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;dropdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRootProps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"country-trigger"&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;dropdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTriggerProps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dropdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dropdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Close&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"country-chips"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dropdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectedItems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"country-chip"&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dropdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItemKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dropdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItemLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;dropdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRemoveButtonProps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;x&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dropdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"country-panel"&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;dropdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getListboxProps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"country-search"&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;dropdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSearchInputProps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dropdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visibleOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
              &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;dropdown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOptionProps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;country-option selected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;country-option&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
              &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;readOnly&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you want the selection, filtering, and grouping engine without prop getters, use &lt;code&gt;useMultiSelectState&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useMultiSelectState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stackline/react-multiselect-dropdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMultiSelectState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;countries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;selectedItems&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;setSelectedItems&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;labelKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itemName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;enableSearchFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The styled component is still available for drop-in usage. The hooks are for teams that want a headless ownership model, including design systems that need to fit React Server Component patterns or drop the bundled CSS entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Forms and controlled state
&lt;/h2&gt;

&lt;p&gt;React does not have &lt;code&gt;ngModel&lt;/code&gt; or &lt;code&gt;formControlName&lt;/code&gt;; a multiselect participates in a form through controlled state. Keep the selected array in state and derive validity from it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectedSkills&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelectedSkills&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Skill&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formIsValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;selectedSkills&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MultiSelectDropdown&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;skills&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;selectedItems&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selectedSkills&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setSelectedSkills&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;skillSettings&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;formIsValid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A note on React 19 specifically: the framework's Actions and form hooks (&lt;code&gt;useActionState&lt;/code&gt;, &lt;code&gt;useFormStatus&lt;/code&gt;, &lt;code&gt;useOptimistic&lt;/code&gt;) are now the recommended way to handle async submission. The selected array is plain React state, so it composes naturally with all of them — read &lt;code&gt;selectedItems&lt;/code&gt; inside an Action, derive an optimistic update from it, or gate a submit button with &lt;code&gt;useFormStatus&lt;/code&gt;. The component does not impose its own form abstraction, which keeps it compatible with whatever submission pattern a screen uses. The docs include both a "template-style forms" example and a "reactive forms" example, named to mirror the Angular line but implemented as ordinary React controlled state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Events
&lt;/h2&gt;

&lt;p&gt;The package exposes a full set of callbacks for selection workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;onChange&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onSelect&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onDeSelect&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onSelectAll&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onDeSelectAll&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onOpen&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onClose&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onScrollToEnd&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onAddFilterNewItem&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onGroupSelect&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onGroupDeSelect&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Selection events are useful when a change needs to trigger downstream behavior — refreshing a report, loading dependent filters, updating query parameters, sending analytics, enabling related controls, or validating dependent fields. The event names are kept stable across versions, so upgrading the React major does not silently break the handlers you already wrote.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ref methods
&lt;/h2&gt;

&lt;p&gt;For imperative control, the component exposes a typed handle through &lt;code&gt;ref&lt;/code&gt;. In React 19 this works without &lt;code&gt;forwardRef&lt;/code&gt; — &lt;code&gt;ref&lt;/code&gt; is a normal prop on function components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dropdownRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MultiSelectDropdownHandle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Country&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;dropdownRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;openDropdown&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;dropdownRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;closeDropdown&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;dropdownRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;focusSearch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;dropdownRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;dropdownRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;deSelectAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;dropdownRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;clearSelection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is handy for wizard-style flows, "clear filters" buttons elsewhere on the page, or opening the dropdown in response to an external event.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lazy loading and dynamic data
&lt;/h2&gt;

&lt;p&gt;Large datasets are where simple dropdowns start failing. Enable lazy loading through settings and append more rows when the list reaches the end:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DropdownSettings&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Select people&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;enableSearchFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lazyLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;labelKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;maxHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;140&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MultiSelectDropdown&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;people&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;selectedItems&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selectedPeople&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setSelectedPeople&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onScrollToEnd&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setPeople&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;loadMorePeople&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This matters for users, customers, products, permissions, locations, departments, catalogs, tags, and reporting dimensions. The docs also include a long-list keyboard-scroll example for large in-memory lists, alongside lazy loading and remote-data examples.&lt;/p&gt;

&lt;p&gt;One detail worth calling out for async data: selected objects are preserved across asynchronous refreshes. When a remote call replaces the option list, previously selected items are merged back into the source instead of being silently dropped because the array reference changed. That is exactly the kind of bug that is invisible in a small demo and painful in production, and it is part of the shared contract with the Angular line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dialogs and overflow containers
&lt;/h2&gt;

&lt;p&gt;A dropdown that works on a simple page can behave differently inside dialogs, modals, drawers, dashboard cards, table filters, and scrollable containers.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;appendToBody: true&lt;/code&gt; or &lt;code&gt;tagToBody: true&lt;/code&gt; when the dropdown sits inside a container that sets &lt;code&gt;overflow: hidden&lt;/code&gt; or &lt;code&gt;overflow: auto&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DropdownSettings&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Country&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dialog dropdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;enableSearchFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;skin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;material&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;appendToBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tagToBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;autoPosition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With body overlay enabled, the open panel renders against &lt;code&gt;document.body&lt;/code&gt;, stays aligned to the original trigger, is sized to the trigger, recalculates on open, scroll, resize, and content changes, and is cleaned up when the dropdown closes or the component unmounts. &lt;code&gt;autoPosition: true&lt;/code&gt; treats &lt;code&gt;position&lt;/code&gt; as a preferred direction: the menu opens upward only when there is meaningfully less room below and enough room above; otherwise it opens below and shrinks the scrollable list height to stay visible without covering the trigger.&lt;/p&gt;

&lt;h2&gt;
  
  
  Theming and skins
&lt;/h2&gt;

&lt;p&gt;Styling is selected through &lt;code&gt;settings.skin&lt;/code&gt;. The React line ships five built-in skins, which is a superset of the Angular line's &lt;code&gt;classic&lt;/code&gt; and &lt;code&gt;material&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Skin&lt;/th&gt;
&lt;th&gt;Usage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;classic&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Compact classic dropdown styling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;material&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Material-style rounded controls and chips&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dark&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Dark UI surfaces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;custom&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CSS-variable starter skin for custom projects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;brand&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stackline brand skin&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Switching skins is just a state change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;setSettings&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;skin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;material&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;settings.theme&lt;/code&gt; is accepted as a legacy alias so existing code keeps rendering, but new usage should configure &lt;code&gt;skin&lt;/code&gt;. The styled component injects its CSS at runtime; if you want full control, the &lt;code&gt;custom&lt;/code&gt; skin is a CSS-variable starting point, and the headless hooks let you drop the bundled CSS entirely and style your own markup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Live functional examples and StackBlitz playground
&lt;/h2&gt;

&lt;p&gt;The React 19 documentation includes real interactive examples running in a live React environment, and the editable playground is a dedicated React 19 StackBlitz tied to the maintained repository, so it stays in sync with the latest source instead of spawning stale forks per example.&lt;/p&gt;

&lt;p&gt;The examples cover, among others:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;basic usage&lt;/li&gt;
&lt;li&gt;keyboard contract&lt;/li&gt;
&lt;li&gt;ARIA state audit&lt;/li&gt;
&lt;li&gt;headless + ARIA&lt;/li&gt;
&lt;li&gt;state hook&lt;/li&gt;
&lt;li&gt;Slots API&lt;/li&gt;
&lt;li&gt;type-safe factory&lt;/li&gt;
&lt;li&gt;async object preservation&lt;/li&gt;
&lt;li&gt;single selection&lt;/li&gt;
&lt;li&gt;search filter and search by property&lt;/li&gt;
&lt;li&gt;custom search from an API&lt;/li&gt;
&lt;li&gt;search and add a new item&lt;/li&gt;
&lt;li&gt;grouped options&lt;/li&gt;
&lt;li&gt;custom rendering (templating)&lt;/li&gt;
&lt;li&gt;template-style and reactive forms&lt;/li&gt;
&lt;li&gt;long-list keyboard scroll&lt;/li&gt;
&lt;li&gt;lazy loading from an API and remote data&lt;/li&gt;
&lt;li&gt;using the control in a list / loop&lt;/li&gt;
&lt;li&gt;using the dropdown inside a dialog&lt;/li&gt;
&lt;li&gt;multiple dropdowns on one page&lt;/li&gt;
&lt;li&gt;dynamic data loading&lt;/li&gt;
&lt;li&gt;methods and events&lt;/li&gt;
&lt;li&gt;disabled mode, selection limits, badge limits&lt;/li&gt;
&lt;li&gt;custom placeholder and styling&lt;/li&gt;
&lt;li&gt;body-overlay auto direction&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These examples are not just static documentation. They let developers check the behavior directly in the browser before installing — how search behaves, how selected values are displayed, how empty states look, how keyboard navigation feels, and how the component behaves inside a dialog. For UI libraries, live examples are part of the trust model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Official React 19 test matrix
&lt;/h2&gt;

&lt;p&gt;The React 19 release was validated in a clean React &lt;code&gt;19.2.4&lt;/code&gt; application using &lt;code&gt;@stackline/react-multiselect-dropdown@19.1.1&lt;/code&gt;. The docs reuse the same examples from that test app, including keyboard navigation, focus, ARIA behavior, badge counters, responsive action buttons, scrollable lists, dialog-safe body overlays, the left-aligned and vertically centered placeholder, guided Slots API customization, headless custom HTML, and the combobox contract checks for Backspace, Escape, focused badge removal, focus, and option ARIA.&lt;/p&gt;

&lt;p&gt;The same core scenarios are validated across the visual skins.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Main settings tested&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;01&lt;/td&gt;
&lt;td&gt;Basic multi&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ enableSearchFilter: true }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;02&lt;/td&gt;
&lt;td&gt;All selected badges visible&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ badgeShowLimit: 10 }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;03&lt;/td&gt;
&lt;td&gt;Single selection&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ singleSelection: true }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;04&lt;/td&gt;
&lt;td&gt;Search by fields&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ searchBy: ['itemName', 'capital'] }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;05&lt;/td&gt;
&lt;td&gt;Grouped options&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ groupBy: 'category', selectGroup: true }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;06&lt;/td&gt;
&lt;td&gt;Selection limit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ limitSelection: 2, badgeShowLimit: 2 }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;07&lt;/td&gt;
&lt;td&gt;Custom rendering&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;renderItem&lt;/code&gt; and &lt;code&gt;renderBadge&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;08&lt;/td&gt;
&lt;td&gt;Search and add item&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ addNewItemOnFilter: true }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;09&lt;/td&gt;
&lt;td&gt;Disabled state&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ disabled: true }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Controlled form validation&lt;/td&gt;
&lt;td&gt;React state and derived validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;Long list with keyboard scroll&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ maxHeight: 140 }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;Local lazy loading&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ lazyLoading: true }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;Dialog and overflow container&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ appendToBody: true, tagToBody: true }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;Body overlay auto direction&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ autoPosition: true, position: 'top' }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;Ref methods&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;openDropdown&lt;/code&gt;, &lt;code&gt;closeDropdown&lt;/code&gt;, &lt;code&gt;selectAll&lt;/code&gt;, &lt;code&gt;clearSelection&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;Slots API custom HTML&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;slots.Trigger&lt;/code&gt;, &lt;code&gt;slots.Option&lt;/code&gt;, &lt;code&gt;slots.Search&lt;/code&gt;, &lt;code&gt;slots.GroupHeader&lt;/code&gt;, &lt;code&gt;slots.MenuFooter&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Publishing the exact scenarios and settings that were tested is a small thing that pays off during adoption: instead of trusting a "tested on React 19" badge, you can see precisely which configurations were exercised, and reproduce them.&lt;/p&gt;

&lt;h2&gt;
  
  
  React version strategy
&lt;/h2&gt;

&lt;p&gt;Each React major receives its own validated package line, locked to one React family. The compatibility table maps each package family to its React family, its peer range, and the tested release window.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package family&lt;/th&gt;
&lt;th&gt;React family&lt;/th&gt;
&lt;th&gt;Peer range&lt;/th&gt;
&lt;th&gt;Tested release window&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;19.x&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;React 19 only&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;gt;=19.0.0 &amp;lt;20.0.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;19.1.1 -&amp;gt; 19.2.4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;18.x&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;React 18 only&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;gt;=18.0.0 &amp;lt;19.0.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;18.0.0 -&amp;gt; 18.3.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;17.x&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;React 17 only&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;gt;=17.0.0 &amp;lt;18.0.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;17.0.0 -&amp;gt; 17.0.2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This improves reproducible builds, compatibility validation, migration planning, and versioned-documentation consistency. The ranges are strictly bounded to the tested React major; the React line does not loosen its range the way the Angular 22 line does, because React's slower, less calendar-driven cadence means there is no fixed next-major date to prepare for. For React teams, predictable compatibility is usually more valuable than optimistic version ranges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adoption checklist
&lt;/h2&gt;

&lt;p&gt;For teams adopting the React 19 line, I would use the following checklist.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Match the package family to your React major
&lt;/h3&gt;

&lt;p&gt;Install the &lt;code&gt;19.x&lt;/code&gt; family for React 19 applications. Keep the package family aligned with the React major your app actually runs.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Install the package
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @stackline/react-multiselect-dropdown@19.1.1 &lt;span class="nt"&gt;--save-exact&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Hold selection in React state
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;useState&lt;/code&gt; for the selected array and update it through &lt;code&gt;onChange&lt;/code&gt;. Treat the component as fully controlled.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Use a stable settings object
&lt;/h3&gt;

&lt;p&gt;Wrap settings in &lt;code&gt;useMemo&lt;/code&gt; so its identity stays stable across renders.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Choose your customization layer
&lt;/h3&gt;

&lt;p&gt;Start with &lt;code&gt;&amp;lt;MultiSelectDropdown /&amp;gt;&lt;/code&gt;. Move to &lt;code&gt;slots&lt;/code&gt; when the layout needs a different shell, and to the headless hooks when the app must own the whole combobox. Use &lt;code&gt;createMultiSelectDropdown&amp;lt;T&amp;gt;()&lt;/code&gt; if a feature or design-system wrapper should bind the item type once.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Configure styling through &lt;code&gt;skin&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Pick from &lt;code&gt;classic&lt;/code&gt;, &lt;code&gt;material&lt;/code&gt;, &lt;code&gt;dark&lt;/code&gt;, &lt;code&gt;custom&lt;/code&gt;, or &lt;code&gt;brand&lt;/code&gt;. Move any &lt;code&gt;theme&lt;/code&gt; usage to &lt;code&gt;skin&lt;/code&gt;; &lt;code&gt;theme&lt;/code&gt; still works as a legacy alias.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Verify keyboard and accessibility
&lt;/h3&gt;

&lt;p&gt;Confirm that space inside search types a space, that tab does not select an option, that escape closes without clearing the field, and that options report consistent &lt;code&gt;aria-selected&lt;/code&gt; and &lt;code&gt;aria-checked&lt;/code&gt;. Configure &lt;code&gt;settings.keyboard&lt;/code&gt; if your app needs different behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Validate real UI scenarios
&lt;/h3&gt;

&lt;p&gt;Test inside modals, scrollable containers, dashboard cards, table filters, and forms with validation. Use &lt;code&gt;appendToBody: true&lt;/code&gt; (or &lt;code&gt;tagToBody: true&lt;/code&gt;) with &lt;code&gt;autoPosition&lt;/code&gt; for dialogs and overflow-clipped containers.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Review large-list and async behavior
&lt;/h3&gt;

&lt;p&gt;Evaluate &lt;code&gt;lazyLoading&lt;/code&gt;, the long-list keyboard-scroll example, &lt;code&gt;maxHeight&lt;/code&gt;, &lt;code&gt;onScrollToEnd&lt;/code&gt;, server-side filtering, and selected-object preservation across async refreshes.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Standardize settings across the app
&lt;/h3&gt;

&lt;p&gt;Create shared settings presets for your design system to avoid slightly different dropdown behavior on different screens.&lt;/p&gt;

&lt;h2&gt;
  
  
  When this component is a good fit
&lt;/h2&gt;

&lt;p&gt;This package is a strong fit when you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React 19 compatibility, validated rather than assumed&lt;/li&gt;
&lt;li&gt;a controlled, predictable selection API (&lt;code&gt;data&lt;/code&gt; in, &lt;code&gt;selectedItems&lt;/code&gt; bound, &lt;code&gt;onChange&lt;/code&gt; out)&lt;/li&gt;
&lt;li&gt;escalating customization: component, slots, headless hooks, and a typed factory&lt;/li&gt;
&lt;li&gt;search, select-all, grouping, and selection limits&lt;/li&gt;
&lt;li&gt;a documented keyboard and ARIA combobox contract&lt;/li&gt;
&lt;li&gt;custom item and badge rendering, plus structural slots&lt;/li&gt;
&lt;li&gt;imperative &lt;code&gt;ref&lt;/code&gt; methods for open, close, focus, select all, and clear&lt;/li&gt;
&lt;li&gt;five built-in skins and full headless styling control&lt;/li&gt;
&lt;li&gt;lazy loading and object preservation for large async lists&lt;/li&gt;
&lt;li&gt;live examples and a StackBlitz playground to evaluate before adoption&lt;/li&gt;
&lt;li&gt;behavioral consistency with the Stackline Angular line for multi-stack teams&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is especially useful for React applications where predictable selection behavior and accessibility matter, and where a design system wants to own rendering without rebuilding selection logic.&lt;/p&gt;

&lt;p&gt;It is probably not the right fit if you want a control built natively around Server Components with no client interactivity. A rich combobox is inherently a client component, and that is correct rather than a limitation. If you want to fit an RSC-heavy design system, the right path is the headless hooks: let a Server Component or an Action provide the data, and use the hook to own the interactive client part. Being clear about that boundary is part of the package being trustworthy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;A good UI component is not only about what appears on the screen.&lt;/p&gt;

&lt;p&gt;In real React projects, the important questions are practical: Does it keep selection state predictable? Does it preserve state across async refreshes? Is it accessible by keyboard and to screen readers? Can a design system customize it at the depth it needs? Are the examples reproducible? Is React compatibility clearly validated?&lt;/p&gt;

&lt;p&gt;Stackline React Multiselect Dropdown for React 19 focuses on those concerns. The package includes search, grouping, select-all support, custom rendering, a guided Slots API, headless hooks, a typed factory, imperative ref methods, lazy loading, five skins, body-overlay positioning, and live React 19 examples running in a real application environment.&lt;/p&gt;

&lt;p&gt;It is also built to be coherent with the Angular line. The combobox and ARIA contract, the skins, the headless philosophy, the per-major versioning, and the live-example model are shared across both ecosystems — with this React line serving as the reference implementation of the shared contract. For teams that run React and Angular side by side, that means a multiselect that behaves the same way in both, which is usually worth more than any single feature.&lt;/p&gt;

&lt;p&gt;For new releases, documentation updates, and the Angular counterpart, visit:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://alexandro.net" rel="noopener noreferrer"&gt;https://alexandro.net&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;p&gt;npm:&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/@stackline/react-multiselect-dropdown" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@stackline/react-multiselect-dropdown&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Documentation (React 19):&lt;br&gt;
&lt;a href="https://alexandro.net/docs/react/multiselect/react-19/#/basic" rel="noopener noreferrer"&gt;https://alexandro.net/docs/react/multiselect/react-19/#/basic&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Live demo / interactive playground (StackBlitz):&lt;br&gt;
&lt;a href="https://stackblitz.com/github/alexandroit/stackline-react-multiselect-react-19?file=src%2Fexamples%2Fbasic%2Fbasic.component.tsx&amp;amp;startScript=start&amp;amp;initialpath=%2Fbasic" rel="noopener noreferrer"&gt;https://stackblitz.com/github/alexandroit/stackline-react-multiselect-react-19?file=src%2Fexamples%2Fbasic%2Fbasic.component.tsx&amp;amp;startScript=start&amp;amp;initialpath=%2Fbasic&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub:&lt;br&gt;
&lt;a href="https://github.com/alexandroit/react-multiselect-dropdown" rel="noopener noreferrer"&gt;https://github.com/alexandroit/react-multiselect-dropdown&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All React lines (React 17 to React 19):&lt;br&gt;
&lt;a href="https://alexandro.net/docs/react/multiselect/" rel="noopener noreferrer"&gt;https://alexandro.net/docs/react/multiselect/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>npm</category>
    </item>
    <item>
      <title>Angular 22 Multiselect Dropdown: A Migration-Friendly Component with Live Functional Tests</title>
      <dc:creator>Alexandro Paixao Marques</dc:creator>
      <pubDate>Mon, 25 May 2026 18:30:45 +0000</pubDate>
      <link>https://dev.to/alexandro_net/angular-21-multiselect-dropdown-a-migration-friendly-component-with-live-functional-tests-5fj6</link>
      <guid>https://dev.to/alexandro_net/angular-21-multiselect-dropdown-a-migration-friendly-component-with-live-functional-tests-5fj6</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmqovgjen03mweedva052.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmqovgjen03mweedva052.gif" alt=" " width="400" height="500"&gt;&lt;/a&gt;&lt;br&gt;
Modern Angular applications rarely need just a dropdown.&lt;/p&gt;

&lt;p&gt;In real projects, a multiselect dropdown usually sits inside something more important: filters, dashboards, reporting tools, permission editors, workflow screens, admin panels, and data-heavy forms where users need to search, group, select, clear, validate, and keep state consistent. It is almost never the feature. It is the control that everything else in the form depends on.&lt;/p&gt;

&lt;p&gt;That is the context behind &lt;strong&gt;Stackline Angular Multiselect Dropdown&lt;/strong&gt;, now available for &lt;strong&gt;Angular 22&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Angular 22 is a meaningful release to target. It landed in early June 2026 as the version where the "signal-first" direction stopped being a roadmap and became the default: zoneless change detection stays the default for new projects, &lt;code&gt;OnPush&lt;/code&gt; becomes the default change-detection strategy for new components, Signal Forms graduate to stable, the Angular Aria accessibility primitives are now stable, the toolchain floor moves up to TypeScript 6, and Vitest replaces Karma/Jasmine as the default test runner. A lot of teams will be upgrading specifically to get onto a fresh long-term-support window with that complete feature set.&lt;/p&gt;

&lt;p&gt;This release of the library is not just about making a dropdown compile on the latest Angular version. The goal is to provide a practical component that can be adopted in real applications, exercised through live examples, and migrated gradually without forcing teams to rewrite every existing template at once — even while the framework underneath them is going through its biggest mental-model shift in years.&lt;/p&gt;

&lt;p&gt;Install the Angular 22 line with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @stackline/angular-multiselect-dropdown
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Links:&lt;/p&gt;

&lt;p&gt;npm:&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/@stackline/angular-multiselect-dropdown" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@stackline/angular-multiselect-dropdown&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Documentation (Angular 22):&lt;br&gt;
&lt;a href="https://alexandro.net/docs/angular/multiselect/angular-22/" rel="noopener noreferrer"&gt;https://alexandro.net/docs/angular/multiselect/angular-22/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Live demo / interactive playground (StackBlitz):&lt;br&gt;
&lt;a href="https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-22?startScript=start&amp;amp;initialpath=%2Fbasic" rel="noopener noreferrer"&gt;https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-22?startScript=start&amp;amp;initialpath=%2Fbasic&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub:&lt;br&gt;
&lt;a href="https://github.com/alexandroit/angular-multiselect-dropdown" rel="noopener noreferrer"&gt;https://github.com/alexandroit/angular-multiselect-dropdown&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For new releases, documentation updates, and upcoming Angular components, visit:&lt;br&gt;
&lt;a href="https://alexandro.net" rel="noopener noreferrer"&gt;https://alexandro.net&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What the library provides
&lt;/h2&gt;

&lt;p&gt;Stackline Angular Multiselect Dropdown is an Angular multiselect component designed for real application forms, dashboards, filters, and enterprise interfaces.&lt;/p&gt;

&lt;p&gt;It supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;single-select and multi-select modes&lt;/li&gt;
&lt;li&gt;search and filtering&lt;/li&gt;
&lt;li&gt;select all and clear all behavior&lt;/li&gt;
&lt;li&gt;grouped options&lt;/li&gt;
&lt;li&gt;custom item templates with selected and ARIA context&lt;/li&gt;
&lt;li&gt;custom badge templates&lt;/li&gt;
&lt;li&gt;a renderless state helper for fully custom HTML&lt;/li&gt;
&lt;li&gt;template-driven forms&lt;/li&gt;
&lt;li&gt;reactive forms&lt;/li&gt;
&lt;li&gt;lazy loading, remote-data hooks, and a virtual-scrolling example for very large lists&lt;/li&gt;
&lt;li&gt;accessibility-focused keyboard navigation, focus handling, and a documented ARIA contract&lt;/li&gt;
&lt;li&gt;CSS and SCSS theming through a &lt;code&gt;skin&lt;/code&gt; system&lt;/li&gt;
&lt;li&gt;versioned documentation per Angular major&lt;/li&gt;
&lt;li&gt;modern selector support with legacy selector compatibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A multiselect component can look simple from the outside, but once it is used across several forms and workflows, replacing it becomes expensive. It affects templates, validation, events, styling, selected state, form reset behavior, focus and keyboard behavior, and sometimes even backend query logic. The cost is rarely in the first screen. It is in the twentieth screen that quietly depends on the behavior of the first.&lt;/p&gt;

&lt;p&gt;That is why compatibility, predictable APIs, accessibility, and safe migration paths matter more than a long feature list.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why this package exists
&lt;/h2&gt;

&lt;p&gt;There are many dropdowns and select components available for Angular, but the hard part in real applications is rarely the first implementation.&lt;/p&gt;

&lt;p&gt;The hard part is keeping the component stable while Angular moves forward, while forms evolve, while UI layouts become more complex, while accessibility requirements get audited, and while existing screens continue to depend on older selectors or configuration patterns.&lt;/p&gt;

&lt;p&gt;This is especially true right now. Angular 22 is the third release in a deliberate transformation. Signals arrived, zoneless change detection went from preview to default, standalone APIs became the norm, and the framework has been steadily reducing how much RxJS and Zone.js machinery you need for everyday UI state. That progress is good, but it also means a lot of production code is mid-migration: partly modern, partly classic, and very sensitive to anything that forces a rewrite.&lt;/p&gt;

&lt;p&gt;This package focuses on a practical set of goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep Angular 22 compatibility clear and validated, not optimistic&lt;/li&gt;
&lt;li&gt;keep the API familiar for existing projects so upgrades do not become rewrites&lt;/li&gt;
&lt;li&gt;support both template-driven and reactive forms&lt;/li&gt;
&lt;li&gt;ship a documented keyboard and ARIA contract instead of leaving accessibility as an afterthought&lt;/li&gt;
&lt;li&gt;provide working examples that can be tested in the browser before installing&lt;/li&gt;
&lt;li&gt;preserve a migration path for older templates and selectors&lt;/li&gt;
&lt;li&gt;expose enough configuration for real dashboard and form use cases, and a renderless mode for the cases that need full control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The intention is not to reinvent how selection works. The intention is to make a commonly needed UI component easier to adopt, validate, and maintain across a framework that is changing quickly underneath it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Angular 22 in context
&lt;/h2&gt;

&lt;p&gt;It helps to be explicit about what Angular 22 actually changes, because it shapes how any third-party component should behave in a 2026 codebase.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;Angular 21&lt;/th&gt;
&lt;th&gt;Angular 22&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Change detection&lt;/td&gt;
&lt;td&gt;Zoneless default for new projects&lt;/td&gt;
&lt;td&gt;Zoneless default; &lt;code&gt;OnPush&lt;/code&gt; is the default strategy for new components&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forms&lt;/td&gt;
&lt;td&gt;Signal Forms introduced as experimental&lt;/td&gt;
&lt;td&gt;Signal Forms stable and production-ready&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accessibility&lt;/td&gt;
&lt;td&gt;Angular Aria in developer preview&lt;/td&gt;
&lt;td&gt;Angular Aria primitives stable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Components&lt;/td&gt;
&lt;td&gt;Standalone the norm&lt;/td&gt;
&lt;td&gt;Selectorless components (import directly in templates) maturing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TypeScript&lt;/td&gt;
&lt;td&gt;5.x supported&lt;/td&gt;
&lt;td&gt;TypeScript 6 required; 5.9 and older dropped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testing&lt;/td&gt;
&lt;td&gt;Vitest opt-in&lt;/td&gt;
&lt;td&gt;Vitest as the default, faster test runner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tooling&lt;/td&gt;
&lt;td&gt;MCP server support&lt;/td&gt;
&lt;td&gt;MCP/AI tooling stabilized&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The takeaway is that most of what the Angular 21 notes described as "coming" or "try this" is now the recommended path. The framework is firmly signal-first, but it is also explicit that this is progressive modernization rather than a forced rewrite — signals coexist with RxJS, and Zone.js is still supported for existing apps.&lt;/p&gt;

&lt;p&gt;Where does a classic settings-driven multiselect fit in that world? Honestly, it is not a signal-native control, and this is a deliberate design choice rather than an oversight. Enterprise Angular codebases still contain large amounts of NgModule-based composition and template-driven or reactive forms that work perfectly well and are not getting rewritten just because &lt;code&gt;OnPush&lt;/code&gt; is now a default. This package leans into that: it ships as an NgModule with the classic API on purpose, so a team can move its build to Angular 22 without simultaneously rewriting every form that touches the dropdown. For the cases that do want a fully modern, custom surface, the renderless state helper (covered below) lets you own the rendering and wiring while the library handles selection, item identity, filtering, object preservation, and ARIA state.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;For Angular 22 projects, install the validated &lt;code&gt;22.x&lt;/code&gt; line with an exact version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @stackline/angular-multiselect-dropdown@22.0.1 &lt;span class="nt"&gt;--save-exact&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pinning the version with &lt;code&gt;--save-exact&lt;/code&gt; keeps compatibility predictable across local environments, CI pipelines, and production builds. The &lt;code&gt;22.0.1&lt;/code&gt; patch keeps the tested Angular 22 behavior, makes &lt;code&gt;&amp;lt;angular-multiselect&amp;gt;&lt;/code&gt; the documented standard selector, keeps &lt;code&gt;&amp;lt;angular2-multiselect&amp;gt;&lt;/code&gt; only as a legacy compatibility alias, and ships the accessibility and keyboard/ARIA interaction contract.&lt;/p&gt;

&lt;p&gt;There is one intentional exception to the usual strict peer ranges. The Angular 22 line uses &lt;code&gt;&amp;gt;=22.0.0 &amp;lt;24.0.0&lt;/code&gt; instead of bounding only to Angular 22. That lets Angular 23 projects install the package on launch day while the dedicated Angular 23 validation line is being prepared, without weakening the compatibility story for everyone else. The package was tested in a real Angular &lt;code&gt;22.0.0&lt;/code&gt; application before publication.&lt;/p&gt;

&lt;h2&gt;
  
  
  Module registration
&lt;/h2&gt;

&lt;p&gt;The component is exposed through &lt;code&gt;AngularMultiSelectModule&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NgModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BrowserModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/platform-browser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FormsModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/forms&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AngularMultiSelectModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stackline/angular-multiselect-dropdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;BrowserModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;FormsModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;AngularMultiSelectModule&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Angular 22 does not force you off NgModules. The framework keeps backward compatibility, and module-based registration is still a first-class way to compose an application. Registering this module remains the supported path, and it is also what makes the component drop cleanly into existing module-based screens that you are not planning to convert to standalone right now. After registering the module, the component can be used in templates with a data source, selected values, and a settings object.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic usage
&lt;/h2&gt;

&lt;p&gt;A typical implementation starts with a list of items, a selected model, and a dropdown configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;countries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;itemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Brazil&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;itemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Canada&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;itemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Portugal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;itemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;United States&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;selectedCountries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;itemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Canada&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;dropdownSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;singleSelection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Select countries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;selectAllText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Select all&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;unSelectAllText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Clear all&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;enableCheckAll&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;enableSearchFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;searchPlaceholderText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;badgeShowLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;maxHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;260&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;showCheckbox&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;noDataLabel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;skin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;classic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;labelKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itemName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tagToBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;angular-multiselect&lt;/span&gt;
  &lt;span class="na"&gt;[data]=&lt;/span&gt;&lt;span class="s"&gt;"countries"&lt;/span&gt;
  &lt;span class="na"&gt;[(ngModel)]=&lt;/span&gt;&lt;span class="s"&gt;"selectedCountries"&lt;/span&gt;
  &lt;span class="na"&gt;[settings]=&lt;/span&gt;&lt;span class="s"&gt;"dropdownSettings"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/angular-multiselect&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps the template compact while allowing most of the behavior to be configured from TypeScript. Note the &lt;code&gt;skin&lt;/code&gt; key: in the Angular 22 line, styling is selected through &lt;code&gt;skin&lt;/code&gt; (&lt;code&gt;classic&lt;/code&gt; or &lt;code&gt;material&lt;/code&gt;). The older &lt;code&gt;theme&lt;/code&gt; key is still accepted as a legacy alias for existing code, but new usage should configure &lt;code&gt;skin&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Selector compatibility
&lt;/h2&gt;

&lt;p&gt;The recommended selector for new code is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;angular-multiselect&amp;gt;&amp;lt;/angular-multiselect&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The package also keeps support for the older selector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;angular2-multiselect&amp;gt;&amp;lt;/angular2-multiselect&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This matters in large Angular applications where selectors may already exist across shared modules, reusable form components, admin screens, internal libraries, and older templates.&lt;/p&gt;

&lt;p&gt;Teams can upgrade gradually instead of rewriting everything in one pass. Existing applications can continue working while new development standardizes around the modern selector. That kind of migration flexibility is exactly what you want during an Angular 22 upgrade, where the framework change itself is already enough work without dragging every component rename into the same pull request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Settings-driven behavior
&lt;/h2&gt;

&lt;p&gt;One of the strongest parts of the package is the settings-driven API.&lt;/p&gt;

&lt;p&gt;Most dropdown behavior can be configured through a single settings object instead of requiring wrapper components or repeated template changes.&lt;/p&gt;

&lt;p&gt;Supported settings include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;singleSelection&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;enableCheckAll&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;enableSearchFilter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;searchBy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;searchPlaceholderText&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;searchAutofocus&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maxHeight&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;badgeShowLimit&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;limitSelection&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;disabled&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;groupBy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;selectGroup&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;showCheckbox&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;noDataLabel&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lazyLoading&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;labelKey&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;primaryKey&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ariaLabel&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keyboard&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;position&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;autoPosition&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;addNewItemOnFilter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;escapeToClose&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;clearAll&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;skin&lt;/code&gt; (legacy alias: &lt;code&gt;theme&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tagToBody&lt;/code&gt; (alias: &lt;code&gt;appendToBody&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Single selection without checkboxes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;dropdownSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;singleSelection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;showCheckbox&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;enableCheckAll&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Select one country&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Selection limit
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;dropdownSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;singleSelection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;limitSelection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;badgeShowLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Select up to 2 countries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Grouped data
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;countries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;itemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Brazil&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;South America&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;itemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Canada&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;North America&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;itemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Portugal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Europe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;dropdownSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;groupBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;region&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;enableSearchFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Select countries by region&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach keeps behavior explicit and discoverable for consumers. A single settings object is also easy to standardize and share across an application, which matters more than it sounds: the most common cause of "the dropdown behaves slightly differently on this screen" is ten slightly different settings objects scattered across ten components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Search and filtering
&lt;/h2&gt;

&lt;p&gt;Search becomes important as soon as datasets grow.&lt;/p&gt;

&lt;p&gt;The package supports filtering through &lt;code&gt;enableSearchFilter&lt;/code&gt;, while &lt;code&gt;searchBy&lt;/code&gt; allows filtering only specific fields.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;dropdownSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;enableSearchFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;searchPlaceholderText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Search countries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;searchBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itemName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;region&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives teams two useful modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;broad search across item properties&lt;/li&gt;
&lt;li&gt;controlled search over selected fields&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Controlled search is useful when items contain internal IDs, flags, system fields, or hidden metadata that should not match the user input. For applications with complex objects, predictable search behavior avoids confusing matches — a user typing "12" should not silently match an internal &lt;code&gt;id&lt;/code&gt; of &lt;code&gt;12&lt;/code&gt; unless you decided that on purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keyboard and accessibility
&lt;/h2&gt;

&lt;p&gt;This is the part of the Angular 22 line that deserves the most attention, and it lines up directly with Angular Aria becoming stable in the framework.&lt;/p&gt;

&lt;p&gt;Accessibility in a multiselect is not a single attribute. It is a behavior contract: what the keyboard does on the trigger versus inside the list, how focus moves, how selected chips are announced, and what screen readers report for each option. The package exposes that contract through a &lt;code&gt;keyboard&lt;/code&gt; settings object so you can configure it instead of fighting it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;dropdownSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Keyboard-tested countries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;enableSearchFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;searchAutofocus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;keyboard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;spaceOptionAction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toggle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;arrows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;backspaceRemovesLastWhenSearchEmpty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;deleteRemovesFocusedBadge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default behavior is designed to match what users expect from a real combobox:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Space on the trigger opens or closes the dropdown.&lt;/li&gt;
&lt;li&gt;Space on an option toggles that option and keeps focus on it.&lt;/li&gt;
&lt;li&gt;Search inputs type a normal space, so searching is never hijacked by selection logic.&lt;/li&gt;
&lt;li&gt;Tab moves focus and never accidentally selects an option.&lt;/li&gt;
&lt;li&gt;Escape closes the list without clearing the selected values.&lt;/li&gt;
&lt;li&gt;Empty-search Backspace does not remove selected values by default, which prevents accidental data loss.&lt;/li&gt;
&lt;li&gt;A focused badge or remove button can be removed intentionally with Backspace or Delete.&lt;/li&gt;
&lt;li&gt;Options expose matching &lt;code&gt;aria-selected&lt;/code&gt; and &lt;code&gt;aria-checked&lt;/code&gt; values, so assistive technology reports a consistent state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Angular line follows the same combobox contract that was validated in the related React 19.1.x work, then exposed through Angular settings. Carrying one tested interaction model across both frameworks means the behavior is not reinvented per platform, and the edge cases that usually break accessibility — space inside search, tab stealing a selection, escape wiping a form field — were handled deliberately rather than by accident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom templates
&lt;/h2&gt;

&lt;p&gt;A multiselect becomes more useful when consumers can control how dropdown items and selected badges are rendered. In the Angular 22 line, the item template context is richer: alongside &lt;code&gt;item&lt;/code&gt;, you also receive &lt;code&gt;label&lt;/code&gt;, &lt;code&gt;selected&lt;/code&gt;, and &lt;code&gt;ariaChecked&lt;/code&gt;, so custom rendering can reflect selection and accessibility state without you recomputing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom item template
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;c-item&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt;
    &lt;span class="na"&gt;let-item=&lt;/span&gt;&lt;span class="s"&gt;"item"&lt;/span&gt;
    &lt;span class="na"&gt;let-label=&lt;/span&gt;&lt;span class="s"&gt;"label"&lt;/span&gt;
    &lt;span class="na"&gt;let-selected=&lt;/span&gt;&lt;span class="s"&gt;"selected"&lt;/span&gt;
    &lt;span class="na"&gt;let-ariaChecked=&lt;/span&gt;&lt;span class="s"&gt;"ariaChecked"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;[attr.data-aria-checked]=&lt;/span&gt;&lt;span class="s"&gt;"ariaChecked"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      {{ label }}
      &lt;span class="nt"&gt;&amp;lt;strong&lt;/span&gt; &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"selected"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Selected&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/c-item&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Custom badge template
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;c-badge&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;let-item=&lt;/span&gt;&lt;span class="s"&gt;"item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"country-chip"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ item.itemName }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/c-badge&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Complete custom template example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;angular-multiselect&lt;/span&gt;
  &lt;span class="na"&gt;[data]=&lt;/span&gt;&lt;span class="s"&gt;"countries"&lt;/span&gt;
  &lt;span class="na"&gt;[(ngModel)]=&lt;/span&gt;&lt;span class="s"&gt;"selectedCountries"&lt;/span&gt;
  &lt;span class="na"&gt;[settings]=&lt;/span&gt;&lt;span class="s"&gt;"dropdownSettings"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;c-badge&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;let-item=&lt;/span&gt;&lt;span class="s"&gt;"item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"country-chip"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ item.itemName }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/c-badge&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;c-item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt;
      &lt;span class="na"&gt;let-item=&lt;/span&gt;&lt;span class="s"&gt;"item"&lt;/span&gt;
      &lt;span class="na"&gt;let-label=&lt;/span&gt;&lt;span class="s"&gt;"label"&lt;/span&gt;
      &lt;span class="na"&gt;let-selected=&lt;/span&gt;&lt;span class="s"&gt;"selected"&lt;/span&gt;
      &lt;span class="na"&gt;let-ariaChecked=&lt;/span&gt;&lt;span class="s"&gt;"ariaChecked"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;{{ label }}&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;small&amp;gt;&lt;/span&gt;{{ item.region }}&lt;span class="nt"&gt;&amp;lt;/small&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/c-item&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/angular-multiselect&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful when applications need avatars, icons, tags, role indicators, custom layouts, region labels, permission markers, account types, or status badges. Most business interfaces eventually need more than plain text rendering, and exposing &lt;code&gt;selected&lt;/code&gt; and &lt;code&gt;ariaChecked&lt;/code&gt; in the template context means the visual state and the accessible state stay in sync instead of drifting apart.&lt;/p&gt;

&lt;h2&gt;
  
  
  Renderless state helper
&lt;/h2&gt;

&lt;p&gt;For the cases where settings and templates are not enough, the Angular 22 line ships a renderless (headless) state helper. This is the part that fits the signal-first, "own your rendering" direction of modern Angular: you write all of the HTML, and the library gives you selection, filtering, item identity, object preservation, and ARIA state.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;AngularMultiselectState&lt;/code&gt; when you want Stackline behavior under fully custom markup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;AngularMultiselectState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;defineAngularMultiselectSettings&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stackline/angular-multiselect-dropdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;CountryOption&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;itemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AngularMultiselectState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CountryOption&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;countries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;selectedItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;countries&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
  &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;defineAngularMultiselectSettings&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CountryOption&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;labelKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itemName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;searchBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itemName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;region&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;ariaLabel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Headless country picker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;selectedItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The documentation includes a dedicated headless and ARIA route that binds the returned trigger, listbox, and option state into fully custom Angular HTML. Practically, this lets a design system build its own visual component on top of a tested selection engine, instead of either fighting the default rendering or rebuilding selection logic from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Forms integration
&lt;/h2&gt;

&lt;p&gt;A production-ready dropdown component must integrate correctly with Angular forms.&lt;/p&gt;

&lt;p&gt;The package supports both template-driven forms and reactive forms.&lt;/p&gt;

&lt;h3&gt;
  
  
  Template-driven forms
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;#form&lt;/span&gt;&lt;span class="err"&gt;="&lt;/span&gt;&lt;span class="na"&gt;ngForm&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;angular-multiselect&lt;/span&gt;
    &lt;span class="na"&gt;[data]=&lt;/span&gt;&lt;span class="s"&gt;"countries"&lt;/span&gt;
    &lt;span class="na"&gt;[(ngModel)]=&lt;/span&gt;&lt;span class="s"&gt;"selectedCountries"&lt;/span&gt;
    &lt;span class="na"&gt;[settings]=&lt;/span&gt;&lt;span class="s"&gt;"dropdownSettings"&lt;/span&gt;
    &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"countries"&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/angular-multiselect&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Reactive forms
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;[formGroup]=&lt;/span&gt;&lt;span class="s"&gt;"userForm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;angular-multiselect&lt;/span&gt;
    &lt;span class="na"&gt;[data]=&lt;/span&gt;&lt;span class="s"&gt;"countries"&lt;/span&gt;
    &lt;span class="na"&gt;[settings]=&lt;/span&gt;&lt;span class="s"&gt;"dropdownSettings"&lt;/span&gt;
    &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"countries"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/angular-multiselect&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In real applications, a multiselect value is not only a visual state. It needs to participate in validation, dirty and touched state, serialization, reset behavior, disabled state, and form submission.&lt;/p&gt;

&lt;p&gt;A word on Angular 22 specifically: Signal Forms are now stable, and many new projects will reach for them. The Angular team has been explicit that forms interoperability is a priority and that the reactive and template-driven systems are not going away. This component integrates through the classic &lt;code&gt;ControlValueAccessor&lt;/code&gt; path, which keeps it working inside existing template-driven and reactive forms during a migration. If a screen is rebuilt around Signal Forms, the renderless state helper is the cleaner bridge, because it hands you the selected items through &lt;code&gt;onChange&lt;/code&gt; and lets you drive a signal yourself. Clean forms integration reduces custom glue code and keeps the component maintainable across large codebases that are part-modern, part-classic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Event system
&lt;/h2&gt;

&lt;p&gt;The component exposes a classic Angular event model for selection workflows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;angular-multiselect&lt;/span&gt;
  &lt;span class="na"&gt;[data]=&lt;/span&gt;&lt;span class="s"&gt;"countries"&lt;/span&gt;
  &lt;span class="na"&gt;[(ngModel)]=&lt;/span&gt;&lt;span class="s"&gt;"selectedCountries"&lt;/span&gt;
  &lt;span class="na"&gt;[settings]=&lt;/span&gt;&lt;span class="s"&gt;"dropdownSettings"&lt;/span&gt;
  &lt;span class="na"&gt;(onSelect)=&lt;/span&gt;&lt;span class="s"&gt;"onItemSelect($event)"&lt;/span&gt;
  &lt;span class="na"&gt;(onDeSelect)=&lt;/span&gt;&lt;span class="s"&gt;"onItemDeSelect($event)"&lt;/span&gt;
  &lt;span class="na"&gt;(onSelectAll)=&lt;/span&gt;&lt;span class="s"&gt;"onSelectAll($event)"&lt;/span&gt;
  &lt;span class="na"&gt;(onDeSelectAll)=&lt;/span&gt;&lt;span class="s"&gt;"onDeSelectAll($event)"&lt;/span&gt;
  &lt;span class="na"&gt;(onAddFilterNewItem)=&lt;/span&gt;&lt;span class="s"&gt;"onAddNewItem($event)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/angular-multiselect&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Selection events are useful when dropdown changes need to trigger downstream behavior, such as refreshing a report, loading dependent filters, updating query parameters, syncing form state, sending analytics events, enabling related controls, or validating dependent fields.&lt;/p&gt;

&lt;p&gt;In many applications, a selection change is not isolated. It is part of a larger workflow. A predictable, stable event contract makes that easier to manage — and keeping the same output names across versions means the upgrade to Angular 22 does not silently break the handlers you already wrote.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lazy loading, virtual scrolling, and large lists
&lt;/h2&gt;

&lt;p&gt;Large datasets are where simple dropdowns usually start failing.&lt;/p&gt;

&lt;p&gt;The package includes lazy loading support and remote-data hooks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;dropdownSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Select items&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;enableSearchFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lazyLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;labelKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;maxHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;260&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This matters for applications dealing with users, customers, products, permissions, locations, departments, catalogs, tags, or reporting dimensions. A component that supports lazy loading can be integrated with local pagination, server-side filtering, remote search workflows, and large-list scenarios.&lt;/p&gt;

&lt;p&gt;The Angular 22 documentation also adds a dedicated virtual-scrolling example for very large option sets, alongside the lazy-loading and remote-data examples. The distinction is worth understanding: lazy loading is about &lt;em&gt;fetching&lt;/em&gt; more data as the user scrolls or searches, while virtual scrolling is about &lt;em&gt;rendering&lt;/em&gt; only the visible rows of a list that is already in memory. Large enterprise lists often need both — fetch in pages, render a window — and having a working example for each keeps you from guessing which problem you actually have.&lt;/p&gt;

&lt;p&gt;One important detail for async data: the Angular 22 line preserves the selected objects across asynchronous refreshes. When a remote call replaces the option list, previously selected items are not silently dropped just because the array reference changed. That is exactly the kind of bug that is invisible in a small demo and painful in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dialogs and overflow containers
&lt;/h2&gt;

&lt;p&gt;Dropdown positioning problems usually appear only in real layouts.&lt;/p&gt;

&lt;p&gt;A dropdown that works on a simple page can behave differently inside dashboard cards, modals, side panels, scrollable containers, constrained widgets, table filters, and embedded panels.&lt;/p&gt;

&lt;p&gt;The package exposes configuration options such as &lt;code&gt;position&lt;/code&gt;, &lt;code&gt;autoPosition&lt;/code&gt;, and &lt;code&gt;tagToBody&lt;/code&gt; (also accepted as &lt;code&gt;appendToBody&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;For sticky cards, constrained containers, or dashboard layouts, keep &lt;code&gt;tagToBody: false&lt;/code&gt; so the dropdown panel stays anchored to the field and does not jump across the page.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;tagToBody: true&lt;/code&gt; when the dropdown is inside Angular Material dialogs, modals, drawers, or any container that sets &lt;code&gt;overflow: hidden&lt;/code&gt; or &lt;code&gt;overflow: auto&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Select countries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;enableSearchFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;skin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;material&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tagToBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;tagToBody: true&lt;/code&gt;, the open panel renders outside the clipping container, stays aligned to the original trigger, keeps the menu surface opaque, recalculates position on scroll and resize, and cleans itself up on close or destroy. The opaque-surface and dialog-safe positioning behavior is carried forward from the Angular 21.2.x baseline, so the upgrade does not regress the hard-won layout fixes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Theming strategy
&lt;/h2&gt;

&lt;p&gt;The package ships with bundled CSS and SCSS, and styling is selected through the &lt;code&gt;skin&lt;/code&gt; setting (&lt;code&gt;classic&lt;/code&gt; or &lt;code&gt;material&lt;/code&gt;). &lt;code&gt;skin&lt;/code&gt; replaces the older &lt;code&gt;theme&lt;/code&gt; key; &lt;code&gt;theme&lt;/code&gt; still works as a legacy alias so existing code keeps rendering.&lt;/p&gt;

&lt;p&gt;A default theme can be added through the Angular styles configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"styles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"node_modules/@stackline/angular-multiselect-dropdown/themes/default.theme.css"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The package also ships a full custom starter theme in both formats, so there are two adoption paths.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fast adoption
&lt;/h3&gt;

&lt;p&gt;Use the bundled CSS theme directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"styles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"node_modules/@stackline/angular-multiselect-dropdown/themes/default.theme.css"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Design-system control
&lt;/h3&gt;

&lt;p&gt;Start from the SCSS theme file, keep it in your application source, and adapt the selectors and tokens to your design system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"styles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"src/styles.scss"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"src/styles/multiselect-dropdown.theme.scss"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Switching skins at runtime is just a settings change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Classic basic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;skin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;classic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;materialSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Material basic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;skin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;material&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives teams a working default while still allowing deeper customization when the component needs to match an internal design system. The &lt;code&gt;css&lt;/code&gt; starter is for teams that want a plain compiled file they can copy and adjust without a Sass pipeline; the &lt;code&gt;scss&lt;/code&gt; starter is for teams that want to take over the component styling completely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Live functional examples and StackBlitz playground
&lt;/h2&gt;

&lt;p&gt;One of the strongest parts of the Angular 22 release is the live functional documentation.&lt;/p&gt;

&lt;p&gt;The Angular 22 documentation includes real interactive examples running in a live Angular environment, and the editable playground is a single Angular 22 StackBlitz with isolated lazy routes. The official links use &lt;code&gt;stackblitz.com/github&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;The Angular 22 examples cover:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;basic multi-select&lt;/li&gt;
&lt;li&gt;single selection&lt;/li&gt;
&lt;li&gt;search and select all&lt;/li&gt;
&lt;li&gt;custom search from an API&lt;/li&gt;
&lt;li&gt;search filter by property&lt;/li&gt;
&lt;li&gt;search and add a new item&lt;/li&gt;
&lt;li&gt;grouped datasets&lt;/li&gt;
&lt;li&gt;custom item and badge templating&lt;/li&gt;
&lt;li&gt;template-driven forms&lt;/li&gt;
&lt;li&gt;reactive forms&lt;/li&gt;
&lt;li&gt;virtual scrolling&lt;/li&gt;
&lt;li&gt;lazy loading from an API&lt;/li&gt;
&lt;li&gt;remote data&lt;/li&gt;
&lt;li&gt;using the control in a list / &lt;code&gt;for&lt;/code&gt; loop&lt;/li&gt;
&lt;li&gt;using the dropdown inside a dialog&lt;/li&gt;
&lt;li&gt;multiple dropdowns on one page&lt;/li&gt;
&lt;li&gt;dynamic data loading&lt;/li&gt;
&lt;li&gt;component methods&lt;/li&gt;
&lt;li&gt;events&lt;/li&gt;
&lt;li&gt;disabled mode&lt;/li&gt;
&lt;li&gt;selection limits&lt;/li&gt;
&lt;li&gt;badge overflow limits&lt;/li&gt;
&lt;li&gt;custom placeholder and styling&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These examples are not just static documentation. They let developers check the behavior directly in the browser before installing the package. That matters because UI components are usually judged by edge cases: how search behaves, how selected values are displayed, how empty states look, how limits are handled, how keyboard navigation feels, and how the component reacts in real interaction. For UI libraries, live examples are part of the trust model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Official Angular 22 test matrix
&lt;/h2&gt;

&lt;p&gt;The Angular 22 release was validated in a real Angular &lt;code&gt;22.0.0&lt;/code&gt; application using &lt;code&gt;@stackline/angular-multiselect-dropdown@22.0.1&lt;/code&gt;. The documentation reuses the same example pattern from that clean test app, including the accessibility-focused keyboard, focus, and ARIA behavior, responsive dropdown width handling, opaque menu surfaces, and dialog-safe positioning carried forward from the Angular 21.2.x line.&lt;/p&gt;

&lt;p&gt;The same twelve scenarios are validated for both the &lt;code&gt;classic&lt;/code&gt; and &lt;code&gt;material&lt;/code&gt; skins.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Main settings tested&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;01&lt;/td&gt;
&lt;td&gt;Basic multi&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ enableSearchFilter: false }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;02&lt;/td&gt;
&lt;td&gt;Search + select all&lt;/td&gt;
&lt;td&gt;search, select all, clear all, events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;03&lt;/td&gt;
&lt;td&gt;Single without checkbox&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ singleSelection: true, showCheckbox: false, enableCheckAll: false }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;04&lt;/td&gt;
&lt;td&gt;Multi without checkbox&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ showCheckbox: false, enableCheckAll: false }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;05&lt;/td&gt;
&lt;td&gt;Selection limit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ limitSelection: 2, badgeShowLimit: 2 }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;06&lt;/td&gt;
&lt;td&gt;Badge overflow&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ badgeShowLimit: 2, maxHeight: 220 }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;07&lt;/td&gt;
&lt;td&gt;Grouped by region&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ groupBy: 'region', maxHeight: 220 }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;08&lt;/td&gt;
&lt;td&gt;Disabled with value&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ disabled: true }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;09&lt;/td&gt;
&lt;td&gt;Empty data&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ noDataLabel: 'No records found' }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Long list with scroll&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ maxHeight: 120, badgeShowLimit: 3 }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;Local lazy loading&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ lazyLoading: true, maxHeight: 120, badgeShowLimit: 3 }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;Item + chip template&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;c-badge&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;c-item&amp;gt;&lt;/code&gt; custom templates&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Publishing the exact scenarios and settings that were tested is a small thing that pays off during adoption: instead of trusting a "tested on Angular 22" badge, you can see precisely which configurations were exercised, and reproduce them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Angular version strategy
&lt;/h2&gt;

&lt;p&gt;Many Angular libraries use broad peer dependency ranges. That can look convenient, but it often creates uncertainty. A package may install successfully while still not being clearly validated against the Angular version used in production.&lt;/p&gt;

&lt;p&gt;This package follows a stricter strategy where each Angular major receives its own validated package line, locked to one framework major. The compatibility table in the repository maps each package family to its Angular family, its peer range, and the tested release window — all the way back from Angular 22 to Angular 2.&lt;/p&gt;

&lt;p&gt;That improves reproducible builds, compatibility validation, migration planning, CI predictability, and versioned-documentation consistency.&lt;/p&gt;

&lt;p&gt;The Angular 22 line is the one deliberate exception. Its peer range is &lt;code&gt;&amp;gt;=22.0.0 &amp;lt;24.0.0&lt;/code&gt; rather than being bounded to Angular 22 alone, so Angular 23 projects can install it on launch day while the dedicated Angular 23 validation line is prepared. Angular 21 stays bounded at &lt;code&gt;&amp;gt;=21.0.0 &amp;lt;22.0.0&lt;/code&gt;. The point is to give Angular 23 early adopters a working install path without pretending the package has already been validated against a framework version that may not have shipped yet.&lt;/p&gt;

&lt;p&gt;For Angular teams, predictable compatibility is usually more valuable than optimistic version ranges, and being explicit about the one place the range is loosened is part of keeping that trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migration checklist
&lt;/h2&gt;

&lt;p&gt;For teams adopting the Angular 22 line, I would use the following checklist.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Get onto a supported Angular version first
&lt;/h3&gt;

&lt;p&gt;Angular follows an 18-month lifecycle (6 months active support, 12 months LTS). Angular 19 reached end-of-life on May 19, 2026, and everything below Angular 20 is unsupported. Separate the framework upgrade from pattern modernization: reach Angular 22 first, then adopt signals, Signal Forms, and selectorless components incrementally.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Install the package
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @stackline/angular-multiselect-dropdown@22.0.1 &lt;span class="nt"&gt;--save-exact&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Register the module
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AngularMultiSelectModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stackline/angular-multiselect-dropdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Add a theme
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"styles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"node_modules/@stackline/angular-multiselect-dropdown/themes/default.theme.css"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Move &lt;code&gt;theme&lt;/code&gt; to &lt;code&gt;skin&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Update settings objects to use &lt;code&gt;skin: 'classic'&lt;/code&gt; or &lt;code&gt;skin: 'material'&lt;/code&gt;. Leave &lt;code&gt;theme&lt;/code&gt; only where you have not migrated yet, since it still works as a legacy alias.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Use the modern selector for new code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;angular-multiselect&amp;gt;&amp;lt;/angular-multiselect&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. Keep the legacy selector only where needed during migration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;angular2-multiselect&amp;gt;&amp;lt;/angular2-multiselect&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  8. Verify form behavior
&lt;/h3&gt;

&lt;p&gt;Check initial selected values, reset behavior, required validation, disabled state, reactive form bindings, and template-driven form bindings. If a screen is being rebuilt on Signal Forms, plan to bridge through the renderless state helper.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Verify keyboard and accessibility
&lt;/h3&gt;

&lt;p&gt;Confirm that space inside the search input types a space, that tab does not select an option, that escape closes without clearing the field, and that options report consistent &lt;code&gt;aria-selected&lt;/code&gt; and &lt;code&gt;aria-checked&lt;/code&gt;. Configure the &lt;code&gt;keyboard&lt;/code&gt; settings object if your application needs different behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Validate real UI scenarios
&lt;/h3&gt;

&lt;p&gt;Test the dropdown inside modals, scrollable containers, dashboard cards, table filters, side panels, and forms with validation messages. Use &lt;code&gt;tagToBody: true&lt;/code&gt; (or &lt;code&gt;appendToBody: true&lt;/code&gt;) for dialogs and overflow-clipped containers.&lt;/p&gt;

&lt;h3&gt;
  
  
  11. Review large-list behavior
&lt;/h3&gt;

&lt;p&gt;For large datasets, evaluate &lt;code&gt;lazyLoading&lt;/code&gt;, virtual scrolling, &lt;code&gt;maxHeight&lt;/code&gt;, search behavior, server-side filtering, scroll-to-end handling, and selected-object preservation across async refreshes.&lt;/p&gt;

&lt;h3&gt;
  
  
  12. Standardize settings
&lt;/h3&gt;

&lt;p&gt;Create shared settings presets for your design system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;defaultMultiselectSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;singleSelection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;enableCheckAll&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;enableSearchFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;badgeShowLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;maxHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;260&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;showCheckbox&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;skin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;classic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;labelKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itemName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This avoids slightly different dropdown behavior across the same application.&lt;/p&gt;

&lt;h2&gt;
  
  
  When this component is a good fit
&lt;/h2&gt;

&lt;p&gt;This package is a strong fit when you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Angular 22 compatibility, validated rather than assumed&lt;/li&gt;
&lt;li&gt;classic Angular module integration that drops into existing NgModule screens&lt;/li&gt;
&lt;li&gt;template-driven and reactive forms support during a migration&lt;/li&gt;
&lt;li&gt;search, select-all, grouping, and selection limits&lt;/li&gt;
&lt;li&gt;a documented keyboard and ARIA contract, aligned with Angular Aria&lt;/li&gt;
&lt;li&gt;customizable item and badge rendering, with selected and ARIA context in the template&lt;/li&gt;
&lt;li&gt;a renderless mode for fully custom HTML on top of a tested selection engine&lt;/li&gt;
&lt;li&gt;theming through CSS and SCSS via a &lt;code&gt;skin&lt;/code&gt; system&lt;/li&gt;
&lt;li&gt;migration-friendly selector compatibility&lt;/li&gt;
&lt;li&gt;lazy loading, virtual scrolling, and object preservation for large async lists&lt;/li&gt;
&lt;li&gt;live examples and a StackBlitz playground to evaluate before adoption&lt;/li&gt;
&lt;li&gt;bounded, per-major Angular version support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is especially useful for Angular applications where stability and migration control matter more than replacing every UI control from scratch.&lt;/p&gt;

&lt;p&gt;It is probably not the right choice if you are starting a brand-new, fully signal-first application with no legacy forms and you want a component built natively around signals and selectorless composition. In that case, either use the renderless state helper as the foundation and build your own surface on top of it, or pick a signal-native control. Being clear about that boundary is part of the package being trustworthy: it is optimized for continuity, not for being the most modern thing on the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;A good UI component is not only about what appears on the screen.&lt;/p&gt;

&lt;p&gt;In real Angular projects, the important questions are practical: Does it integrate cleanly with forms? Does it preserve state correctly across async refreshes? Is it accessible by keyboard and to screen readers? Can teams migrate without rewriting templates? Does it handle larger datasets? Can the design system customize it? Are the examples reproducible? Is Angular compatibility clearly validated?&lt;/p&gt;

&lt;p&gt;Stackline Angular Multiselect Dropdown for Angular 22 focuses on those concerns. The package includes search, grouping, select-all support, custom templates, a documented keyboard and ARIA contract, a renderless state helper, form integration, theming through skins, lazy loading and virtual scrolling, and live Angular 22 examples running in a real application environment.&lt;/p&gt;

&lt;p&gt;The migration path is also practical. Existing applications can keep their NgModule registration, classic API, and legacy selectors while newer projects adopt the modern selector and renderless mode progressively — which is exactly the posture Angular 22 itself takes toward modernization. For teams building or upgrading Angular 22 applications during the signal-first transition, that combination of validated compatibility, accessibility, customization, and reproducible live examples makes the package a solid option for production use.&lt;/p&gt;

&lt;p&gt;For new releases, documentation updates, and upcoming Angular components, visit:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://alexandro.net" rel="noopener noreferrer"&gt;https://alexandro.net&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;p&gt;npm:&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/@stackline/angular-multiselect-dropdown" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@stackline/angular-multiselect-dropdown&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Documentation (Angular 22):&lt;br&gt;
&lt;a href="https://alexandro.net/docs/angular/multiselect/angular-22/" rel="noopener noreferrer"&gt;https://alexandro.net/docs/angular/multiselect/angular-22/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Live demo / interactive playground (StackBlitz):&lt;br&gt;
&lt;a href="https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-22?startScript=start&amp;amp;initialpath=%2Fbasic" rel="noopener noreferrer"&gt;https://stackblitz.com/github/alexandroit/stackline-angular-multiselect-angular-22?startScript=start&amp;amp;initialpath=%2Fbasic&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub:&lt;br&gt;
&lt;a href="https://github.com/alexandroit/angular-multiselect-dropdown" rel="noopener noreferrer"&gt;https://github.com/alexandroit/angular-multiselect-dropdown&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All Angular lines (Angular 2 to Angular 22):&lt;br&gt;
&lt;a href="https://alexandro.net/docs/angular/multiselect/" rel="noopener noreferrer"&gt;https://alexandro.net/docs/angular/multiselect/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>npm</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
