Angular Material 13 Multi Select Chips Component Tutorial

Angular Material 13 Chips component example; In this tutorial, we will demonstrate how to implement dynamic chips selection using an autocomplete search bar in the Angular application.

We will also show you some other useful angular chips examples, such as drag and drop Chips and how to add chips selection in the form input field.

To create and display chips selection, we will use the Angular Material Ui library in the angular app.

Chips allow users to enter information, make selections, filter content, or invoke actions. Chips are not that difficult to develop, primarily if you use angular material in Angular app development.

To drag and drop chips selection example, autocomplete chips selection example we will incorporate material library.

It is a profound UI library created by Google in 2014. It is exclusively designed for the Angular environment, and it lets you develop an angular app in an attractive, consistent, and user-friendly manner.

How to Create Multi Select Chips in Angular using Material Library

  • Step 1: Install Angular Project
  • Step 2: Add Angular Material Module
  • Step 3: Build Material Module File
  • Step 4: Create Autocomplete Chips Component
  • Step 5: Create Drag and Drop Chips
  • Step 6: Build Chips with Input
  • Step 7: View in Browser

Install Angular Project

Angular CLI allows you develop angular application, it provides the environment for angular app building.

Run the command to install the angular app.

npm install -g @angular/cli

You are now ready to install the new angular application for creating chips functionality.

ng new ng-material-demo

Get inside the project folder:

cd ng-material-demo

Disable Strict Angular TypeStrict Errors

The latest version of Angular comes with strict mode, therefore, you need to update the compilerOptions and angularCompilerOptions in tsconfig.json file for disabling the strict mode:

{
   “strict”: false, 
   "noImplicitReturns": false 
   "strictTemplates": false
}

Add Angular Material Module

We are now ready to add the angular material library in angular app, make sure to execute the given command:

ng add @angular/material

In order to set up the material’s prebuilt theme, material typography and browser animation we can answer the given questions based on the given reference.

  1. Choose a prebuilt theme name or “custom” for a custom theme:

    You can choose from prebuilt material design themes or set up an extensible custom theme.

  2. Set up global Angular Material typography styles:

    Whether to apply the global typography styles to your application.

  3. Set up browser animations for Angular Material:

    Importing the BrowserAnimationsModule into your application enables Angular’s animation system. Declining this will disable most of Angular Material’s animations.

Open the src/styles.scss file and add the material’s theme CSS link.

@import "~@angular/material/prebuilt-themes/indigo-pink.css";

Build Material Module File

In the src/ folder, create /material.module.ts file. In this file we will be importing all the possible material user interface modules, though we are concerned with MatChipsModule.

import { NgModule } from '@angular/core';
import { A11yModule } from '@angular/cdk/a11y';
import { CdkAccordionModule } from '@angular/cdk/accordion';
import { ClipboardModule } from '@angular/cdk/clipboard';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { PortalModule } from '@angular/cdk/portal';
import { ScrollingModule } from '@angular/cdk/scrolling';
import { CdkStepperModule } from '@angular/cdk/stepper';
import { CdkTableModule } from '@angular/cdk/table';
import { CdkTreeModule } from '@angular/cdk/tree';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatBadgeModule } from '@angular/material/badge';
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
import { MatButtonModule } from '@angular/material/button';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { MatCardModule } from '@angular/material/card';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatChipsModule } from '@angular/material/chips';
import { MatStepperModule } from '@angular/material/stepper';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatDialogModule } from '@angular/material/dialog';
import { MatDividerModule } from '@angular/material/divider';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatGridListModule } from '@angular/material/grid-list';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatListModule } from '@angular/material/list';
import { MatMenuModule } from '@angular/material/menu';
import { MatNativeDateModule, MatRippleModule } from '@angular/material/core';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatRadioModule } from '@angular/material/radio';
import { MatSelectModule } from '@angular/material/select';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatSliderModule } from '@angular/material/slider';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table';
import { MatTabsModule } from '@angular/material/tabs';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatTreeModule } from '@angular/material/tree';
import { OverlayModule } from '@angular/cdk/overlay';

@NgModule({
  exports: [
    A11yModule,
    CdkAccordionModule,
    ClipboardModule,
    CdkStepperModule,
    CdkTableModule,
    CdkTreeModule,
    DragDropModule,
    MatAutocompleteModule,
    MatBadgeModule,
    MatBottomSheetModule,
    MatButtonModule,
    MatButtonToggleModule,
    MatCardModule,
    MatCheckboxModule,
    MatChipsModule,
    MatStepperModule,
    MatDatepickerModule,
    MatDialogModule,
    MatDividerModule,
    MatExpansionModule,
    MatGridListModule,
    MatIconModule,
    MatInputModule,
    MatListModule,
    MatMenuModule,
    MatNativeDateModule,
    MatPaginatorModule,
    MatProgressBarModule,
    MatProgressSpinnerModule,
    MatRadioModule,
    MatRippleModule,
    MatSelectModule,
    MatSidenavModule,
    MatSliderModule,
    MatSlideToggleModule,
    MatSnackBarModule,
    MatSortModule,
    MatTableModule,
    MatTabsModule,
    MatToolbarModule,
    MatTooltipModule,
    MatTreeModule,
    OverlayModule,
    PortalModule,
    ScrollingModule,
  ],
})

export class MaterialModule {}

Go to app/ folder and open the app.module.ts file, and add the CUSTOM_ELEMENTS_SCHEMA, MaterialModule, FormsModule, and ReactiveFormsModule modules.

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';

import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MaterialModule } from '../material.module';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    FormsModule,
    ReactiveFormsModule,
    MaterialModule,
  ],
  providers: [],
  bootstrap: [AppComponent],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
})

export class AppModule {}

Create Autocomplete Chips Component

To create the autocomplete chips component, you have to use the mat-from-field directive; inside this prop, you have to define the mat-chip-list, and mat-chip directive with ngFor loo.

This will iterate over the chips values that will define in the typescript template, so add following code in app.component.html file:

<mat-form-field class="example-chip-list" appearance="fill">
  <mat-label>Favorite Fruits</mat-label>
  <mat-chip-list #chipList aria-label="Fruit selection">
    <mat-chip
      *ngFor="let fruit of fruits"
      (removed)="remove(fruit)">
      {{fruit}}
      <button matChipRemove>
        <mat-icon>cancel</mat-icon>
      </button>
    </mat-chip>
    <input
      placeholder="New fruit..."
      #fruitInput
      [formControl]="fruitCtrl"
      [matAutocomplete]="auto"
      [matChipInputFor]="chipList"
      [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
      (matChipInputTokenEnd)="add($event)">
  </mat-chip-list>
  <mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
    <mat-option *ngFor="let fruit of filteredFruits | async" [value]="fruit">
      {{fruit}}
    </mat-option>
  </mat-autocomplete>
</mat-form-field>

Import essential modules in the typescript template, then create certain functions to make the chip autocomplete work in angular.

Update suggested code in app.component.ts file:

import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { Component, ElementRef, ViewChild } from '@angular/core';
import { FormControl } from '@angular/forms';
import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
import { MatChipInputEvent } from '@angular/material/chips';
import { Observable } from 'rxjs';
import { map, startWith } from 'rxjs/operators';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})

export class AppComponent {
  separatorKeysCodes: number[] = [ENTER, COMMA];
  fruitCtrl = new FormControl();
  filteredFruits: Observable<string[]>;
  fruits: string[] = ['Lemon'];
  allFruits: string[] = ['Apple', 'Lemon', 'Lime', 'Orange', 'Strawberry'];

  @ViewChild('fruitInput') fruitInput: ElementRef<HTMLInputElement>;

  constructor() {
    this.filteredFruits = this.fruitCtrl.valueChanges.pipe(
      startWith(null),
      map((fruit: string | null) =>
        fruit ? this._filter(fruit) : this.allFruits.slice()
      )
    );
  }

  add(event: MatChipInputEvent): void {
    const value = (event.value || '').trim();

    // Add our fruit
    if (value) {
      this.fruits.push(value);
    }

    // Clear the input value
    event.chipInput!.clear();

    this.fruitCtrl.setValue(null);
  }

  remove(fruit: string): void {
    const index = this.fruits.indexOf(fruit);

    if (index >= 0) {
      this.fruits.splice(index, 1);
    }
  }

  selected(event: MatAutocompleteSelectedEvent): void {
    this.fruits.push(event.option.viewValue);
    this.fruitInput.nativeElement.value = '';
    this.fruitCtrl.setValue(null);
  }

  private _filter(value: string): string[] {
    const filterValue = value.toLowerCase();

    return this.allFruits.filter((fruit) =>
      fruit.toLowerCase().includes(filterValue)
    );
  }
}

Create Drag and Drop Chips

To create the drag and drop chips functionality, we will be using the chips’ api options such as cdkDropList, and cdkDropListOrientation. The ngFor directive will display the chips values in angular through the CDK drag directive.

Add following code in app.component.html file:

<mat-chip-list
  class="example-chip"
  cdkDropList
  cdkDropListOrientation="horizontal"
  (cdkDropListDropped)="drop($event)"
>
  <mat-chip class="example-box" cdkDrag *ngFor="let vegetable of vegetables">
    {{ vegetable.name }}
  </mat-chip>
</mat-chip-list>

Update suggested code in app.component.ts file:

import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { Component } from '@angular/core';

export interface Vegetable {
  name: string;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})

export class AppComponent {
  vegetables: Vegetable[] = [
    { name: 'apple' },
    { name: 'banana' },
    { name: 'strawberry' },
    { name: 'orange' },
    { name: 'kiwi' },
    { name: 'cherry' },
  ];

  drop(event: CdkDragDrop<Vegetable[]>) {
    moveItemInArray(this.vegetables, event.previousIndex, event.currentIndex);
  }
}

Build Chips with Input

You can add the chips feature to the input field, add the mat-form-field directive as a wrapper, define the mat-chip-list, and loop through the chips values so that chips can be shown in the form input.

Add following code in app.component.html file:

<mat-form-field class="example-chip-list" appearance="fill">
  <mat-label>Favorite Fruits</mat-label>
  <mat-chip-list #chipList aria-label="Fruit selection">
    <mat-chip *ngFor="let fruit of fruits" (removed)="remove(fruit)">
      {{fruit.name}}
      <button matChipRemove>
        <mat-icon>cancel</mat-icon>
      </button>
    </mat-chip>
    <input placeholder="New fruit..."
           [matChipInputFor]="chipList"
           [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
           [matChipInputAddOnBlur]="addOnBlur"
           (matChipInputTokenEnd)="add($event)">
  </mat-chip-list>
</mat-form-field>

Update suggested code in app.component.ts file:

import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { Component } from '@angular/core';
import { MatChipInputEvent } from '@angular/material/chips';

export interface Fruit {
  name: string;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})

export class AppComponent {
  addOnBlur = true;
  readonly separatorKeysCodes = [ENTER, COMMA] as const;
  fruits: Fruit[] = [{ name: 'Lemon' }, { name: 'Lime' }, { name: 'Apple' }];

  add(event: MatChipInputEvent): void {
    const value = (event.value || '').trim();

    // Add our fruit
    if (value) {
      this.fruits.push({ name: value });
    }

    // Clear the input value
    event.chipInput!.clear();
  }

  remove(fruit: Fruit): void {
    const index = this.fruits.indexOf(fruit);

    if (index >= 0) {
      this.fruits.splice(index, 1);
    }
  }
}

View in Browser

Execute the following command to run the Angular app.

ng serve

You can check the chips feature in the browser through the given url:

http://localhost:4200

Angular Material 13 Multi Select Chips Component Tutorial

Conclusion

In this guide, we learned how to build simple chips in angular, how to create and show autocomplete chips in angular and how to make basic chips in the form input field using the angular material library.