Features | Getting started | Virtual scroll | FAQ | Docs
An Ionic component similar to Ionic Select, that allows to search items, including async search, infinite scrolling, virtual scrolling and more.
Which package am I looking at? This is the Angular component. There is also a separate Stencil-based line that ships web components for vanilla JS and other frameworks. The instructions below are for the Angular package.
| ionic-selectable | Ionic | Angular |
|---|---|---|
| 7.x | 8 | 20 – 22 |
| 6.x | 7 | 16 |
| 4.x | 4 | — |
| 3.x | 3 | — |
7.x is a standalone build. The component, the modal and all template
directives are standalone, and Ionic is consumed through
@ionic/angular/standalone. It works both in apps bootstrapped with
provideIonicAngular() and in apps still using IonicModule.forRoot().
The package is published in Angular's partial compilation mode, so a build made with Angular 21 links cleanly into Angular 20, 21 and 22 applications.
- Single selection
- Multiple selection
- Search items
- Search items asynchronously
- Search by several item fields
- Forms
- InfiniteScroll
- Virtual scroll, with group headers
- Templates
- Grouping items
- Editing, adding and deleting items
- Disabling items
npm install ionic-selectable --save@angular/cdk is a peer dependency — it powers the virtual scroll viewport —
so install it too if your app doesn't have it already:
npm install @angular/cdk --saveBecause the component is standalone, import it directly into whichever component uses it:
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { IonItem, IonLabel } from '@ionic/angular/standalone';
import { IonicSelectableComponent } from 'ionic-selectable';
@Component({
selector: 'app-home',
templateUrl: './home.page.html',
imports: [FormsModule, IonItem, IonLabel, IonicSelectableComponent]
})
export class HomePage { }If you use the template directives (ionicSelectableItemTemplate,
ionicSelectableValueTemplate, …), import them alongside the component, or
import IonicSelectableModule, which re-exports the component and every
directive at once:
import { IonicSelectableModule } from 'ionic-selectable';
@Component({
// ...
imports: [IonicSelectableModule]
})
export class HomePage { }IonicSelectableModule is also still a valid NgModule import, so existing
module-based apps keep working unchanged:
@NgModule({
imports: [IonicSelectableModule]
})
export class AppModule { }For Angular 16 standalone component
import { IonicSelectableComponent } from 'ionic-selectable';
@Component({
...,
standalone: true,
imports: [IonicSelectableComponent]
})
<ion-item>
<ion-label>Port</ion-label>
<ionic-selectable
[(ngModel)]="port"
[items]="ports"
itemValueField="id"
itemTextField="name"
[canSearch]="true"
(onChange)="portChange($event)">
</ionic-selectable>
</ion-item>import { Component } from '@angular/core';
import { IonicSelectableComponent } from 'ionic-selectable';
interface Port {
id: number;
name: string;
}
@Component({ /* ... */ })
export class HomePage {
ports: Port[] = [
{ id: 1, name: 'Tokai' },
{ id: 2, name: 'Vladivostok' },
{ id: 3, name: 'Navlakhi' }
];
port: Port | undefined;
portChange(event: { component: IonicSelectableComponent; value: any }) {
console.log('port:', event.value);
}
}Explore the docs and FAQ to learn more about its features, and run the demo app in this repo to see every option in action.
Set hasVirtualScroll when the list is long enough that rendering every item
hurts. The modal then renders the list through an Angular CDK
virtual scroll viewport,
keeping only the visible rows in the DOM.
<ionic-selectable
[(ngModel)]="port"
[items]="ports"
itemValueField="id"
itemTextField="name"
[hasVirtualScroll]="true"
[canSearch]="true">
</ionic-selectable>Groups and virtual scroll can be used together. Groups are flattened into a
single stream of header and item rows, so groupValueField / groupTextField
work exactly as they do in a regular list:
<ionic-selectable
[(ngModel)]="port"
[items]="ports"
itemValueField="id"
itemTextField="name"
groupValueField="country.id"
groupTextField="country.name"
[hasVirtualScroll]="true">
</ionic-selectable>When the items aren't grouped with groupValueField, headers can still be
inserted with virtualScrollHeaderFn. It receives each item and returns the
header text to render before it, or undefined for no header:
<ionic-selectable
[hasVirtualScroll]="true"
[virtualScrollHeaderFn]="getGroupText">
</ionic-selectable>getGroupText(port: Port, index: number, ports: Port[]) {
if (index === 0 || port.country.id !== ports[index - 1].country.id) {
return port.country.name;
}
return undefined;
}Rows are rendered at a fixed height, which defaults to 40px. Both items and
group headers are pinned to it. Change it with virtualScrollApproxItemHeight,
which accepts a number of pixels or a px string:
<ionic-selectable [hasVirtualScroll]="true" [virtualScrollApproxItemHeight]="56">
</ionic-selectable>The value is also exposed to CSS as --ionic-selectable-virtual-item-height on
the viewport, so custom item templates can lay themselves out against it.
- Virtual scroll and
hasInfiniteScrollare mutually exclusive. With virtual scroll enabled, infinite scroll is not rendered andenableInfiniteScroll()/disableInfiniteScroll()/endInfiniteScroll()are no-ops. scrollToTop()andscrollToBottom()operate on the viewport.- The viewport is the scrolling element, so
ion-contentscrolling is turned off while virtual scroll is on. - Searching resets the viewport back to the first row.
The repo contains both the library (src/app/components/ionic-selectable) and
a demo app covering every feature (src/app/pages).
npm install # install dependencies
npm start # serve the demo app
npm run build # build the demo app
npm test # run unit tests
npm run lint # lint
npm run build.ng # build the publishable library into dist/Always publish the built package from dist/, never from the repo root
(the root only contains sources and would ship raw .ts files without a
module/exports entry). A prepublishOnly script fails on purpose if you try:
npm version <x.y.z> --no-git-tag-version # bump version in package.json
npm run build.ng # build into dist/ (copies package.json, README, LICENSE)
cd dist && npm publish # publish the built packageFor contribution guidelines please refer to Contribution.
If you find this component useful, please star the repo to let others know that it's reliable. Also, share it with friends and colleagues who might find it useful as well. Thank you 😄
