IonxSearchSelect

September 29, 2025 · View on GitHub

A modern Search & Select component for Angular + Ionic.
Built with Standalone Components, Angular Signals, and full CVA (ControlValueAccessor) support.

Angular Ionic TypeScript License

IonxSearchSelect Demo

✨ Features

  • 🔎 Searchable select with keyboard navigation
  • 🌀 Works with Reactive Forms and Template-driven Forms
  • 🧩 Can be used standalone without Angular Forms
  • 🌍 Built-in i18n (EN/DE) with overrides
  • 🎨 Ionic design, ships as Angular standalone library
  • ♻️ No RxJS required (pure Signals API)

📦 Installation

This library requires @ionic/angular and ionicons as peer dependencies.

Install them step by step:

npm install @ionic/angular ionicons

Then install the library:

npm install ionx-search-select

Peer dependencies:

  • Angular ≥ 20
  • Ionic ≥ 8

🚀 Usage

1. Reactive Forms (FormControl)

// demo.page.ts
import { FormControl } from '@angular/forms';
import { SelectOption } from 'ionx-search-select';

type Id = string;

@Component({
  /* ... */
})
export class DemoPage {
  city = new FormControl<Id | null>(null);

  cityOptions: SelectOption<Id>[] = [
    { value: 'ber', label: 'Berlin' },
    { value: 'ham', label: 'Hamburg' },
    { value: 'muc', label: 'Munich' },
    { value: 'cgn', label: 'Cologne', disabled: true },
    { value: 'fra', label: 'Frankfurt' },
  ];
}
<ionx-search-select [options]="cityOptions" placeholder="Choose a city…" [formControl]="city">
</ionx-search-select>

<p>Selected: {{ city.value }}</p>

2. Template-driven Forms ([(ngModel)])

// demo.page.ts
selectedCity: string | null = null;

cityOptions: SelectOption<string>[] = [
  { value: 'ber', label: 'Berlin' },
  { value: 'ham', label: 'Hamburg' },
  { value: 'muc', label: 'Munich' },
  { value: 'fra', label: 'Frankfurt' },
];
<ionx-search-select [options]="cityOptions" placeholder="Choose a city…" [(ngModel)]="selectedCity">
</ionx-search-select>

<p>Selected: {{ selectedCity }}</p>

3. Standalone (without Angular Forms)

// demo.page.ts
selectedCity: string | null = null;

cityOptions: SelectOption<string>[] = [
  { value: 'ber', label: 'Berlin' },
  { value: 'ham', label: 'Hamburg' },
  { value: 'muc', label: 'Munich' },
];
<ionx-search-select
  [options]="cityOptions"
  [value]="selectedCity"
  (changed)="selectedCity = $event"
>
</ionx-search-select>

<p>Selected: {{ selectedCity }}</p>

⚙️ Inputs

InputTypeDefaultDescription
optionsSelectOption<T>[][]Options to display
placeholderstringSelect…Trigger label & modal title
multiplebooleanfalseEnable multi select
clearablebooleantrueShow Clear button
closeOnSelectbooleantrueAuto close after select (single)
locale'en' | 'de''en'Built-in i18n
i18nPartial<IonxSearchSelectI18n>{}Override any text
searchPlaceholderstring | nullnullExplicit search placeholder
displayWith(opt: SelectOption<T>) => stringo => o.labelCustom label renderer
compareWith(a: T, b: T) => booleana===bCustom equality fn
trackBy(o: SelectOption<T>) => unknowno.valueTrackBy fn

📤 Outputs

OutputPayloadDescription
changedT | T[] | nullValue changed
openedChangebooleanModal open/close state
openedvoidModal opened
closedvoidModal closed
clearedvoidClear clicked

🔑 Interfaces

export interface SelectOption<T = unknown> {
  value: T;
  label: string;
  disabled?: boolean;
}

export type IonxSearchSelectI18n = {
  clear: string;
  done: string;
  selected: string;
  noResults: string;
  search: string;
  searchAriaLabel: string;
  closeAriaLabel: string;
};

🛠️ Development

Build the library:

ng build ionx-search-select

Run the demo app:

ng serve demo

Run unit tests:

ng test

📄 License

MIT – free to use, modify and distribute.