<mat-select> is a form control used for selecting a value from a set of options. It is same as the original <select> element. We will discuss more about the selections in Material Design Imagination.
To add selection options, add <mat-select> elements to <mat-select>. Angular content supports the use of <mat-form-field> inside the native <select> element. Add the matNativeControl attribute to the <select> element to use a parent selection inside <mat-form-field>.
app.component.html
<h4>Basic mat-select</h4>
<mat-form-field appearance="fill">
<mat-label>Favorite food</mat-label>
<mat-select>
<mat-option *ngFor="let food of foods" [value]="food.value">
{{food.viewValue}}
</mat-option>
</mat-select>
</mat-form-field>
<h4>Basic native select</h4>
<mat-form-field appearance="fill">
<mat-label>Cars</mat-label>
<select matNativeControl required>
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</select>
</mat-form-field>
app.component.ts
import {Component} from '@angular/core';
interface Food {
value: string;
viewValue: string;
}
/**
* @title Basic select
*/
@Component({
selector: 'select-overview-example',
templateUrl: 'select-overview-example.html',
})
export class SelectOverviewExample {
foods: Food[] = [
{value: 'steak-0', viewValue: 'Steak'},
{value: 'pizza-1', viewValue: 'Pizza'},
{value: 'tacos-2', viewValue: 'Tacos'}
];
}
Output:
Getting and setting the select value
The <mat-select> supports 2-way binding to the value property without the need for Angular forms.
app.component.html
<mat-form-field appearance="fill">
<mat-label>Select an option</mat-label>
<mat-select [(value)]="selected">
<mat-option>None</mat-option>
<mat-option value="option1">Option 1</mat-option>
<mat-option value="option2">Option 2</mat-option>
<mat-option value="option3">Option 3</mat-option>
</mat-select>
</mat-form-field>
<p>You selected: {{selected}}</p>
app.component.ts
import {Component} from '@angular/core';
/** @title Select with 2-way value binding */
@Component({
selector: 'select-value-binding-example',
templateUrl: 'select-value-binding-example.html',
})
export class SelectValueBindingExample {
selected = 'option2';
Output:
Both <mat-select> and <select> support Formsmodule (NgModel) and ReactiveFormsModule (FormControl, FormGroup, etc.).
app.component.html
<form>
<h4>mat-select</h4>
<mat-form-field appearance="fill">
<mat-label>Favorite food</mat-label>
<mat-select [(ngModel)]="selectedValue" name="food">
<mat-option *ngFor="let food of foods" [value]="food.value">
{{food.viewValue}}
</mat-option>
</mat-select>
</mat-form-field>
<p> Selected food: {{selectedValue}} </p>
<h4>native html select</h4>
<mat-form-field appearance="fill">
<mat-label>Favorite car</mat-label>
<select matNativeControl [(ngModel)]="selectedCar" name="car">
<option value="" selected></option>
<option *ngFor="let car of cars" [value]="car.value">
{{car.viewValue}}
</option>
</select>
</mat-form-field>
<p> Selected car: {{selectedCar}} </p>
</form>
import {Component} from '@angular/core';
interface Food {
value: string;
viewValue: string;
}
interface Car {
value: string;
viewValue: string;
}
/**
* @title Select in a form
*/
@Component({
selector: 'select-form-example',
templateUrl: 'select-form-example.html',
})
export class SelectFormExample {
selectedValue: string;
selectedCar: string;
foods: Food[] = [
{value: 'steak-0', viewValue: 'Steak'},
{value: 'pizza-1', viewValue: 'Pizza'},
{value: 'tacos-2', viewValue: 'Tacos'}
];
cars: Car[] = [
{value: 'volvo', viewValue: 'Volvo'},
{value: 'saab', viewValue: 'Saab'},
{value: 'mercedes', viewValue: 'Mercedes'}
];
}
Output:
Form field Features
There are a number of <mat-form-field> features that are used with both <select> and <mat-select>. It includes error messages, prefixes, hint text and suffixes.
app.component.html
<h5>mat select</h5>
<mat-form-field appearance="fill">
<mat-label>Favorite animal</mat-label>
<mat-select [formControl]="animalControl" required>
<mat-option>--</mat-option>
<mat-option *ngFor="let animal of animals" [value]="animal">
{{animal.name}}
</mat-option>
</mat-select>
<mat-error *ngIf="animalControl.hasError('required')">Please choose an animal</mat-error>
<mat-hint>{{animalControl.value?.sound}}</mat-hint>
</mat-form-field>
<h4>native html select</h4>
<mat-form-field appearance="fill">
<mat-label>Select your car (required)</mat-label>
<select matNativeControl required [formControl]="selectFormControl">
<option label="--select something --"></option>
<option value="saab">Saab</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</select>
<mat-error *ngIf="selectFormControl.hasError('required')">
This field is required
</mat-error>
<mat-hint>You can pick up your favorite car here</mat-hint>
</mat-form-field>
import {Component} from '@angular/core';
import {FormControl, Validators} from '@angular/forms';
interface Animal {
name: string;
sound: string;
}
/** @title Select with form field features */
@Component({
selector: 'select-hint-error-example',
templateUrl: 'select-hint-error-example.html',
})
export class SelectHintErrorExample {
animalControl = new FormControl('', Validators.required);
selectFormControl = new FormControl('', Validators.required);
animals: Animal[] = [
{name: 'Dog', sound: 'Woof!'},
{name: 'Cat', sound: 'Meow!'},
{name: 'Cow', sound: 'Moo!'},
{name: 'Fox', sound: 'Wa-pa-pa-pa-pa-pa-pow!'},
];
}
Output:
To set a static placeholder
The placeholder is shown when the <mat-form-field> label is floating or the <mat-select> label is empty. It is used to give the user an additional indication about the value of their selection. The placeholder specifies by setting the placeholder attribute on the <mat-select> element. In some cases, that <mat-form-field> uses a placeholder as a label.
Disabling the select or individual options
We can disable the entire selection or individual options in a selection by using the Disable property on the <select> or <mat-select> and the <option> or <mat-option> elements.
app.component.html
<p>
<mat-checkbox [formControl]="disableSelect">Disable select</mat-checkbox>
</p>
<h4>mat-select</h4>
<mat-form-field appearance="fill">
<mat-label>Choose an option</mat-label>
<mat-select [disabled]="disableSelect.value">
<mat-option value="option1">Option 1</mat-option>
<mat-option value="option2" disabled>Option 2 (disabled)</mat-option>
<mat-option value="option3">Option 3</mat-option>
</mat-select>
</mat-form-field>
<h4>native html select</h4>
<mat-form-field appearance="fill">
<mat-label>Choose an option</mat-label>
<select matNativeControl [disabled]="disableSelect.value">
<option value="" selected></option>
<option value="volvo">Volvo</option>
<option value="saab" disabled>Saab</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</select>
</mat-form-field>
app.component.ts
import {Component} from '@angular/core';
import {FormControl} from '@angular/forms';
/** @title Disabled select */
@Component({
selector: 'select-disabled-example',
templateUrl: 'select-disabled-example.html',
})
export class SelectDisabledExample {
disableSelect = new FormControl(false);
}
Output:
Creating groups of options
The <mat-optgroup> element is used to group common options under a subheading. The group name will set by using the label property of <mat-optgroup>. Like individual <mat-options> elements, the whole <mat-Optgroup> can be disabled or enabled by setting the Disable property.
app.component.html
<h4>mat-select</h4>
<mat-form-field appearance="fill">
<mat-label>Pokemon</mat-label>
<mat-select [formControl]="pokemonControl">
<mat-option>-- None --</mat-option>
<mat-optgroup *ngFor="let group of pokemonGroups" [label]="group.name"
[disabled]="group.disabled">
<mat-option *ngFor="let pokemon of group.pokemon" [value]="pokemon.value">
{{pokemon.viewValue}}
</mat-option>
</mat-optgroup>
</mat-select>
</mat-form-field>
<h4>native html select</h4>
<mat-form-field appearance="fill">
<mat-label>Cars</mat-label>
<select matNativeControl>
<optgroup label="Swedish Cars">
<option value="volvo">volvo</option>
<option value="saab">Saab</option>
</optgroup>
<optgroup label="German Cars">
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</optgroup>
</select>
</mat-form-field>
import {Component} from '@angular/core';
import {FormControl} from '@angular/forms';
interface Pokemon {
value: string;
viewValue: string;
}
interface PokemonGroup {
disabled?: boolean;
name: string;
pokemon: Pokemon[];
}
/** @title Select with option groups */
@Component({
selector: 'select-optgroup-example',
templateUrl: 'select-optgroup-example.html',
})
export class SelectOptgroupExample {
pokemonControl = new FormControl();
pokemonGroups: PokemonGroup[] = [
{
name: 'Grass',
pokemon: [
{value: 'bulbasaur-0', viewValue: 'Bulbasaur'},
{value: 'oddish-1', viewValue: 'Oddish'},
{value: 'bellsprout-2', viewValue: 'Bellsprout'}
]
},
{
name: 'Water',
pokemon: [
{value: 'squirtle-3', viewValue: 'Squirtle'},
{value: 'psyduck-4', viewValue: 'Psyduck'},
{value: 'horsea-5', viewValue: 'Horsea'}
]
},
{
name: 'Fire',
disabled: true,
pokemon: [
{value: 'charmander-6', viewValue: 'Charmander'},
{value: 'vulpix-7', viewValue: 'Vulpix'},
{value: 'flareon-8', viewValue: 'Flareon'}
]
},
{
name: 'Psychic',
pokemon: [
{value: 'mew-9', viewValue: 'Mew'},
{value: 'mewtwo-10', viewValue: 'Mewtwo'},
]
}
];
}
Output:
Multiple Selections
The <mat-select> defaults to single-select mode but can be configured to allow different classes by setting other properties. When using <mat-select> in multiple selection mode, its value will be a sorted list of all selected values instead of a single value.
app.component.html
<mat-form-field appearance="fill">
<mat-label>Toppings</mat-label>
<mat-select [formControl]="toppings" multiple>
<mat-option *ngFor="let topping of toppingList" [value]="topping">{{topping}}</mat-option>
</mat-select>
</mat-form-field>
app.component.ts
import {Component} from '@angular/core';
import {FormControl} from '@angular/forms';
/** @title Select with multiple selection */
@Component({
selector: 'select-multiple-example',
templateUrl: 'select-multiple-example.html',
})
export class SelectMultipleExample {
toppings = new FormControl();
toppingList: string[] = ['Extra cheese', 'Mushroom', 'Onion', 'Pepperoni', 'Sausage', 'Tomato'];
}
Output:
Customizing the trigger label
If you have to display a custom trigger label inside a <mat-select>, you can use <mat-select-trigger> element.
Disabling the ripple effect
When the user clicks on <mat-option> then the ripple animation is shown. It could disable by the disableRipple property on <mat-select>.
app.component.html
<mat-form-field appearance="fill">
<mat-label>Select an option</mat-label>
<mat-select disableRipple>
<mat-option value="1">Option 1</mat-option>
<mat-option value="2">Option 2</mat-option>
<mat-option value="3">Option 3</mat-option>
</mat-select>
</mat-form-field>
app.component.ts
import {Component} from '@angular/core';
/** @title Select with no option ripple */
@Component({
selector: 'select-no-ripple-example',
templateUrl: 'select-no-ripple-example.html',
})
export class SelectNoRippleExample {}
Output:
Adding custom styles to the dropdown panel
To styling the dropdown panel, has a panel Class property which is used to apply additional CSS classes to the dropdown panel.
app.component.html
<mat-form-field appearance="fill">
<mat-label>Panel color</mat-label>
<mat-select [formControl]="panelColor"
panelClass="example-panel-{{panelColor.value}}">
<mat-option value="red">Red</mat-option>
<mat-option value="green">Green</mat-option>
<mat-option value="blue">Blue</mat-option>
</mat-select>
</mat-form-field>
app.component.ts
import {Component, ViewEncapsulation} from '@angular/core';
import {FormControl} from '@angular/forms';
/**
* @title Select with custom panel styling
*/
@Component({
selector: 'select-panel-class-example',
templateUrl: 'select-panel-class-example.html',
styleUrls: ['select-panel-class-example.css'],
// Encapsulation has to be disabled in order for the
// component style to apply to the select panel.
encapsulation: ViewEncapsulation.None,
})
export class SelectPanelClassExample {
panelColor = new FormControl('red');
}
app.component.css
.example-panel-red.mat-select-panel {
background: rgba(255, 0, 0, 0.5);
}
.example-panel-green.mat-select-panel {
background: rgba(0, 255, 0, 0.5);
}
.example-panel-blue.mat-select-panel {
background: rgba(0, 0, 255, 0.5);
}
Output:
Changing when error messages are shown
The <mat-form-field> allows us to associate error messages with the <select> or <mat-select>. By default, error messages are came when the control is invalid or the user has interacted with the element. If we want to override the behavior, we can use the errorStateMatcher property <mat-select>. The property takes an instance of the ErrorStateMatcher object
app.component.html
<h4>mat-select</h4>
<mat-form-field appearance="fill">
<mat-label>Choose one</mat-label>
<mat-select [formControl]="selected" [errorStateMatcher]="matcher">
<mat-option>Clear</mat-option>
<mat-option value="valid">Valid option</mat-option>
<mat-option value="invalid">Invalid option</mat-option>
</mat-select>
<mat-hint>Errors appear instantly!</mat-hint>
<mat-error *ngIf="selected.hasError('required')">You must make a selection</mat-error>
<mat-error *ngIf="selected.hasError('pattern') && !selected.hasError('required')">
Your selection is invalid
</mat-error>
</mat-form-field>
<h4>native html select</h4>
<mat-form-field class="demo-full-width" appearance="fill">
<mat-label>Choose one</mat-label>
<select matNativeControl [formControl]="nativeSelectFormControl" [errorStateMatcher]="matcher">
<option value=""></option>
<option value="valid" selected>Valid option</option>
<option value="invalid">Invalid option</option>
</select>
<mat-error *ngIf="nativeSelectFormControl.hasError('required')">You must make a selection</mat-error>
<mat-error *ngIf="nativeSelectFormControl.hasError('pattern') && !nativeSelectFormControl.hasError('required')">
Your selection is invalid
</mat-error>
</mat-form-field>
import {Component} from '@angular/core';
import {FormControl, FormGroupDirective, NgForm, Validators} from '@angular/forms';
import {ErrorStateMatcher} from '@angular/material/core';
/** Error when invalid control is touched or submitted. */
export class MyErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const isSubmitted = form && form.submitted;
return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
}
}
/** @title Select with a custom ErrorStateMatcher */
@Component({
selector: 'select-error-state-matcher-example',
templateUrl: 'select-error-state-matcher-example.html',
})
export class SelectErrorStateMatcherExample {
selected = new FormControl('valid', [
Validators.required,
Validators.pattern('valid'),
]);
selectFormControl = new FormControl('valid', [
Validators.required,
Validators.pattern('valid'),
]);
nativeSelectFormControl = new FormControl('valid', [
Validators.required,
Validators.pattern('valid'),
]);
matcher = new MyErrorStateMatcher();
}
Output:
A global error condition matching can be specified by setting the ErrorStateMatcher provider. It applies to all inputs. ShowOnDirtyErrorStateMatcher is available to show globally available input errors when the input is invalid.
@NgModule({
providers: [
{provide: ErrorStateMatcher, useClass: ShowOnDirtyErrorStateMatcher}
]
})
Keyboard interaction
DOWN_ARROW: It focuses on the next option
UP_ARROW: It focuses on the previous option
ENTER or SPACE: It selects on the focused item
Accessibility
The <mat-select> component has “combobox”, the dropdown panel has “listbox” and options inside select panel have “option”.
The native <select> offers the best accessibility, and screen-readers support it.
Troubleshooting
Error: Cannot change multiple modes of select after initialization
It occurs if we try to bind different properties on the dynamic value to <mat-select>.
<mat-select *ngIf="isMultiple" multiple>
...
</mat-select>
<mat-select *ngIf="!isMultiple">
...
</mat-select>
Error: Value is an array in multiple-selection mode
It occurs when we assign a value other than null, undefined, or an array to the <mat-select multiple>.
For example, mySelect.value = ‘option1’.
Leave a Reply