See Demo page.
Warning: Do not use versions 15.2.0, 16.0.0, 17.0.0, 18.0.0, 19.0.0, 20.0.0 as they contain unresolved issues
| Angular | ng-select |
|---|---|
| >=22.0.0 <23.0.0 | v23.x.x |
| >=21.0.0 <22.0.0 | v21.x.x |
| >=20.0.0 <21.0.0 | <=15.1.3, >=20.0.1 |
| >=19.0.0 <20.0.0 | v14.x |
| >=18.0.0 <19.0.0 | v13.x |
| >=17.0.0 <18.0.0 | v12.x |
| >=16.0.0 <17.0.0 | v11.x |
| >=15.0.0 <16.0.0 | v10.x |
| >=14.0.0 <15.0.0 | v9.x |
| >=13.0.0 <14.0.0 | v8.x |
| >=12.0.0 <13.0.0 | v7.x |
| >=11.0.0 <12.0.0 | v6.x |
| >=10.0.0 <11.0.0 | v5.x |
| >=9.0.0 <10.0.0 | v4.x |
| >=8.0.0 <9.0.0 | v3.x |
| >=6.0.0 <8.0.0 | v2.x |
| v5.x.x | v1.x |
ng-select supports all browsers supported by Angular. For current list, see https://angular.io/guide/browser-support#browser-support. This includes the following specific versions:
Chrome 2 most recent versions
Firefox latest and extended support release (ESR)
Edge 2 most recent major versions
Safari 2 most recent major versions
iOS 2 most recent major versions
Android 2 most recent major versions
- Features
- Getting started
- Documentation and examples
- Dropdown panel rendering
- Contributing
- Development
- Inspiration
- Custom binding to property or object
- Custom option, label, header and footer templates
- Virtual Scroll support with large data sets (>5000 items).
- Infinite scroll
- Keyboard navigation
- Multiselect
- Flexible autocomplete with client/server filtering
- Custom search
- Custom tags
- CDK overlay positioning (top-layer rendering, no clipping)
- Group items
- Output events
- Accessibility
- Signal Forms, Reactive Forms and Template-driven Forms
- Good base functionality test coverage
- Themes
Library is under active development and may have API breaking changes for subsequent major versions after 1.0.0.
npm install --save @ng-select/ng-select @angular/cdkyarn add @ng-select/ng-select @angular/cdkpnpm add @ng-select/ng-select @angular/cdkimport { NgLabelTemplateDirective, NgOptionTemplateDirective, NgSelectComponent } from '@ng-select/ng-select';
import { FormField } from '@angular/forms/signals';
@Component({
selector: 'example',
standalone: true,
templateUrl: './example.component.html',
styleUrl: './example.component.scss',
imports: [FormField, NgLabelTemplateDirective, NgOptionTemplateDirective, NgSelectComponent],
})
export class ExampleComponent {}For Reactive Forms, import ReactiveFormsModule. For Template-driven Forms, import FormsModule.
import { NgSelectModule } from '@ng-select/ng-select';
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [AppComponent],
imports: [NgSelectModule, FormsModule],
bootstrap: [AppComponent],
})
export class AppModule {}To allow customization and theming, ng-select bundle includes only generic styles that are necessary for correct layout and positioning. To get full look of the control, include one of the themes in your application. If you're using the Angular CLI, you can add this to your styles.scss or include it in .angular-cli.json (Angular v5 and below) or angular.json (Angular v6 onwards).
@import '~@ng-select/ng-select/themes/default.theme.css';
// ... or
@import '~@ng-select/ng-select/themes/material.theme.css';You can also set global configuration and localization messages by injecting NgSelectConfig service, typically in your root component, and customize the values of its properties in order to provide default values.
constructor(private config: NgSelectConfig) {
this.config.notFoundText = 'Custom not found';
// set the bindValue to global config when you use the same
// bindValue in most of the place.
// You can also override bindValue for the specified template
// by defining `bindValue` as property
// Eg : <ng-select bindValue="some-new-value"></ng-select>
this.config.bindValue = 'value';
}ng-select supports Signal Forms, Reactive Forms and Template-driven Forms in Angular 22 applications.
Define the options shared by these examples:
@Component({...})
export class ExampleComponent {
readonly cars = [
{ id: 1, name: 'Volvo' },
{ id: 2, name: 'Saab' },
{ id: 3, name: 'Opel' },
{ id: 4, name: 'Audi' },
];
}Bind a field from the tree returned by form(). A raw signal value is not a valid formField binding.
import { signal } from '@angular/core';
import { form, FormField } from '@angular/forms/signals';
readonly carModel = signal({ selectedCarId: null as number | null });
readonly carForm = form(this.carModel);<ng-select [items]="cars" bindLabel="name" bindValue="id" [formField]="carForm.selectedCarId" />import { FormControl, ReactiveFormsModule } from '@angular/forms';
readonly selectedCarId = new FormControl<number | null>(null);<ng-select [items]="cars" bindLabel="name" bindValue="id" [formControl]="selectedCarId" />import { FormsModule } from '@angular/forms';
selectedCarId: number | null = null;<!--Using ng-option and for loop-->
<ng-select [(ngModel)]="selectedCarId">
@for (car of cars; track car.id) {
<ng-option [value]="car.id">{{car.name}}</ng-option>
}
</ng-select>
<!--Using items input-->
<ng-select [items]="cars" bindLabel="name" bindValue="id" [(ngModel)]="selectedCarId" />For more detailed examples see Demo page
If you are using SystemJS, you should also adjust your configuration to point to the UMD bundle.
In your systemjs config file, map needs to tell the System loader where to look for ng-select:
map: {
'@ng-select/ng-select': 'node_modules/@ng-select/ng-select/bundles/ng-select.umd.js',
}Full documentation, live examples and the complete API reference live on the docs site:
- Getting started
- Examples — data sources, bindings, forms, search, tags, templates, multiselect, grouping, virtual scroll and more
- API reference — inputs, outputs and methods for
NgSelectComponent,NgSelectConfig, template directives andNgOptionHighlightDirective - Styling
- Change detection notes
Since v24 the dropdown panel is positioned by Angular CDK Overlay instead of the previous hand-rolled geometry code. @angular/cdk is a peer dependency — install it alongside the library. There is nothing to configure; every dropdown renders in an overlay attached to the document body, stays anchored to the select while any ancestor scrolls, resizes with the select, and dropdownPosition="auto" measures the real rendered panel (including header/footer templates) when deciding between top and bottom.
Things to know when migrating:
- DOM location. The panel is no longer a child of
<ng-select>in the DOM — it lives inside.cdk-overlay-container(the same situation asappendTo="body"produced before). CSS that scoped panel styles through an ancestor of the select, like.my-wrapper ng-dropdown-panel { ... }, will no longer match. The panel still receives the select'sclass,[class], and[ngClass]values, and you can add panel-only classes withpanelClass. Scope panel styles through those classes:.my-select-class.ng-dropdown-panel .ng-option { ... }, or use separate host and panel classes:class="my-select" panelClass="my-select-panel". appendTochanged meaning;popoveris a deprecated no-op. Overlay rendering already solves the clipping/stacking problems both existed for, so most usages ofappendTocan simply be removed. It still works — but it now controls where the overlay lives in the DOM (ancestor-scoped styles, stacking context, focus containment) rather than how the panel is positioned; painting and positioning stay viewport-based either way.popoverhas no effect anymore (the overlay uses the native Popover API top layer automatically) and logs a one-time dev-mode warning.- Stacking / z-index. The hardcoded panel
z-index: 1050is gone. In browsers with the native Popover API (all evergreen browsers), the CDK renders the overlay in the top layer, which paints above everyz-index— including Bootstrap modals — with no configuration. In older browsers the panel falls back into.cdk-overlay-containerwith the CDK defaultz-index: 1000(declared in thecdk-overlayCSS layer). If you need the fallback to beat a higher stacking context such as a Bootstrap modal (z-index: 1055), raise the container in your global styles:.cdk-overlay-container { z-index: 1056; }— unlayered author CSS wins over the CDK's layered default regardless of specificity. - Custom themes. The shipped themes no longer position the panel (
top: 100%,bottom: 100%,left: 0and friends were removed — margins, borders, shadows and radii remain). The library neutralizes those offsets for panels rendered in the overlay, so themes copied from older versions keep working, but you should remove positional offsets from.ng-dropdown-panelrules when you update your own theme.
Contributions are welcome. You can start by looking at issues with label Help wanted or creating new Issue with proposal or bug report. Note that we are using https://conventionalcommits.org/ commits format.
Perform the clone-to-launch steps with these terminal commands.
git clone https://github.com/ng-select/ng-select
cd ng-select
pnpm i
pnpm run start
pnpm test
or
pnpm test:watch
To release to npm just run ./release.sh, of course if you have permissions ;)
This component is inspired by React select and Virtual scroll. Check theirs amazing work and components :)