How to make single checkbox select from mat-selection-list
. Similar to radio button which accepts one value from group of values.

- 177
- 1
- 11

- 231
- 1
- 2
- 4
15 Answers
Components >= 9.1.0
Selection list now supports a single selection mode directly. Enable it with the multiple input set to false.
<mat-selection-list [multiple]="false">...
Components < 9.1.0
You have to set SelectionModel for selectedOptions property of component reference on init.
@ViewChild(MatSelectionList, {static: true})
private selectionList: MatSelectionList;
ngOnInit() {
this.selectionList.selectedOptions = new SelectionModel<MatListOption>(false);
}
This way you can define initially selected values too.
export declare class SelectionModel<T> {
constructor(_multiple?: boolean, initiallySelectedValues?: T[], _emitChanges?: boolean);
}

- 4,474
- 1
- 24
- 30
-
Sorry for the question. I am new to angular. How do you reference the selection list in the component? How do you get this.selectionList? – Juanjo Oct 04 '18 at 15:24
-
1Look at ViewChild decorator: https://angular.io/api/core/ViewChild. With that you can reference any component or element in template. – hovado Oct 04 '18 at 15:36
-
how to change order of the checkbox column as first before details? – sainu Feb 08 '19 at 11:28
-
I can't use the same way in @ViewChildren with QueryList. Is there any solution for that? – Sasindu Lakshitha Dec 20 '19 at 06:19
-
@SasinduLakshitha You don't have to use '@ViewChildren' since 9.1.0 version. See edited answer. – hovado Feb 26 '20 at 11:23
What you'd need to do is:
- Listen for
selectionChange
- Clear all with
deselectAll()
method - Set it as selected again
I modified the original example from the API page, added a ViewChild for the selection list and subscribe to the selectionChange
event.
ngOnInit(){
this.shoes.selectionChange.subscribe((s: MatSelectionListChange) => {
this.shoes.deselectAll();
s.option.selected = true;
});
// WARNING: Don't attempt to do the following to select the value
// it won't trigger the value change event so it will remain unchecked
// this.shoes.selectedOptions.select(s.option);
// If interested source is here :
// https://github.com/angular/material2/blob/fa4ddd0a13461b2f846e114fd09f8f4e21b814b1/src/lib/list/selection-list.ts
}
Working sample: https://stackblitz.com/edit/angular-i3pfu2-6n5cnt

- 140,023
- 84
- 646
- 689
-
Note: I reported the issue with selectionModel.select not working and it has already has a push fixed - so in future this should work – Simon_Weaver Feb 10 '18 at 21:20
-
Good solution if you need the checkboxes because multiple= flase hides them. – cedricblaser01 Jun 23 '21 at 13:54
To begin with, mat-selection-list
is not suitable for a single-value selection, as it veers away from its intent:
Checkboxes in a group are non-exclusive options; more than one checkbox in a group can be checked at any given time
What you're looking for is the radio-button element itself, because semantically it stands for:
A radio button is one of a group of controls representing mutually-exclusive choices
Unfortunately Angular Material does not include a mat-radio-list
component. But you can still achieve it by including a mat-radio-button
inside you mat-list-item
. This will provide best practice, as it denotes to the user that the list in view is intended for mutually-exclusive choices (unlike checkboxes that denote multiple-choice). And since the radio buttons are updating a single variable, you get exclusivity:
<mat-list role="list">
<mat-list-item role="listitem" *ngFor="let x of [0,1,2]; let i = index">
<mat-radio-button [value]="i" (change)="selection = $event.value">
Item {{x}}
</mat-radio-button>
</mat-list-item>
</mat-list>

- 392
- 3
- 8
-
2I agree that you should be using radio buttons instead of checkboxes if it's single-selection -- that's the point of radio styling, after all -- but it's kind of a coincidence that `mat-radio-button` works inside of `mat-list-item`, and can break down if you use more advanced features. For example, try adding a `matListIcon` to your list -- now the radio button is constrained inside a "line container" and goes crazy as soon as you click it. We need a `mat-radio-list`, I think. – Coderer Dec 24 '18 at 12:58
Just set the multiple option of MatSelectionList to false:
ngOnInit() {
this.links.selectedOptions._multiple = false;
}
and you're done. Also by doing this you will be able to deselect the selected checkbox.

- 86
- 1
- 2
- 8
Bit late to the party, but here's a solution I came up with using a directive to extend the mat-selection-list
behaviour.
import { SelectionModel } from "@angular/cdk/collections";
import { Directive, Host, Input, OnChanges } from "@angular/core";
import { MatListOption, MatSelectionList } from "@angular/material/list";
@Directive({
selector: "mat-selection-list[multiple]"
})
export class MatSelectionListMultipleDirective implements OnChanges {
private matSelectionList: MatSelectionList;
@Input()
public multiple: boolean;
constructor(@Host() matSelectionList: MatSelectionList) {
this.matSelectionList = matSelectionList;
}
public ngOnChanges(): void {
if (this.multiple) {
this.matSelectionList.selectedOptions = new SelectionModel<MatListOption>(true, this.matSelectionList.selectedOptions.selected);
}
else {
let selected = this.matSelectionList.selectedOptions.selected.splice(0, 1);
this.matSelectionList.selectedOptions = new SelectionModel<MatListOption>(false, selected);
}
}
}
Which you can use like this...
<mat-selection-list [multiple]="false">
...
</mat-selection-list>
Ideally we would have a radio control instead of the checkbox, but I think this workaround is OK until the angular material team support this officially.

- 41
- 1
-
-
-
If you can not upgrade to the newest Angular Material, and perhaps want to use *ngIf on your mat-selection-list this is the cleanest solution! – Véger Lóránd Jun 19 '20 at 13:24
In order to make single checkbox select from mat-selection-list if you are not using Angular Material v6+ here is the workaround i used : Let's say we have a list of categories checkboxes.
In your HTML :
<mat-selection-list>
<mat-list-option (selectionChange)="handleSelection($event, category)" *ngFor="let category of categories" [value]="category">
<span >{{category.name}}</span>
</mat-list-option>
</mat-selection-list>
In your .TS :
handleSelection(event, categorySelected) {
if (event.selected) {
event.source.selectionList.options.toArray().forEach(element => {
if (element.value.name!= categorySelected.name) {
element.selected = false;
}
});
}
}
The key here is to use the property selectionChange on the MatListOption and not MatSelectionList.

- 57
- 8
-
2Tried a half dozen solutions. This is the only solution that worked for me. My `mat-selection-list` is displayed in a modal that uses `ngIf` to show/hide, so registering list as a `@ViewComponent` does nothing. The mat-angular team should have made this a simple attribute. – jboothe Jun 21 '18 at 20:43
From a philosophical and UX perspective, you need to use radio buttons. This is the only way to provide user-friendly "as expected" behavior.

- 1,224
- 1
- 7
- 6
If you're using ngFor for each mat-checkbox, you can do something similar to following in HTML template:
<ng-container *ngFor="let address of person.addresses; let i = index">
<mat-checkbox [checked]="personCheckedIndex === i" (change)="customerCheckboxChange($event, i)"></mat-checkbox>
</ng-container>
and in TS:
public personCheckedIndex = -1;
// Called from template when checkbox value changes
personCheckboxChange(event: MatCheckboxChange, index: number) {
// This allows only one checkbox to be checked among each checkbox
this.personCheckedIndex = event.checked ? index : -1;
}

- 363
- 1
- 6
- 16
you can declare the [selected]
attribute of mat-list-option
for example:
<mat-selection-list #list>
<mat-list-option *ngFor="let item of myList"
[(mgModel)]="selectedOption"
[selected]="item.id === selectedOption.id"
[value]="item">
{{item.name}}
</mat-list-option>
</mat-selection-list>
by this way you reach just one selection without changing any MatSelectionList hidden property.
Also you can do it by replacing ngModel
with controller logic,
by this way you will save the last selection object in class variable.
<mat-list-option (selectionChange)="onChange($event)"`

- 3,017
- 1
- 37
- 43
What you need is probably a <mat-radio-group>
rather than a <mat-selection-list>
, Its a list of options but only one option can be selected. an example can be found at the Angular Material docs.
But be advised that instead of a checkbox you'll get a radio button.

- 7,612
- 5
- 28
- 42
try this:
ts:
import { Component, OnInit, ViewChild} from '@angular/core';
import { MatSelectionList } from '@angular/material';
@Component({
selector : 'app-xxx',
templateUrl: './xxx.component.html'
})
export class xxxComponent implements OnInit {
public data: Object[] = [ {name : "name 1" }, {name : "name 2" }, {name : "name 3" }, {name : "name 4" } ];
@ViewChild('element_id') names_list: MatSelectionList;
ngOnInit() {
// only if the element is visible on the page, otherwise move this block and execute it until the list is displayed
setTimeout(()=>{
this.names_list.selectedOptions._multiple = false;
},0);
}
}
template:
<mat-selection-list #element_id>
<mat-list-option *ngFor="let d of data">
{{ d.name }}
</mat-list-option>
</mat-selection-list>

- 35
- 3
you can use 'mat-checkbox' instead of 'mat-selection-list' and play with click event like this:
HTML
<div *ngFor=" ... loop">
<mat-checkbox #checkBoxes (click)="changeCheckBox()">
</mat-checkbox>
</div>
TS
@ViewChildren('checkBoxes') checkBoxes: QueryList<MatCheckbox>;
changeCheckBox() {
this.checkBoxes.filter((checkbox: MatCheckbox) =>
checkbox.checked === true
)[0].checked = false;
}
remember that all check boxes default value is unchecked.

- 1,662
- 17
- 30
Starting Angular Material 9.1.0, selection list supports a single selection mode. Enable it with the multiple
input set to false
: https://material.angular.io/components/list/api#MatSelectionList

- 1,796
- 3
- 14
- 7
-
1Angular 11 [multiple]="false" not working for me got error: ` error NG8002: Can't bind to 'multiple' since it isn't a known property of 'mat-selection-list'.` any ideas? – Juliano Vargas Oct 20 '21 at 08:35
Try this: I've got it working with a tick, changing css
:host ::ng-deep .mat-radio-outer-circle{
border-radius:2px;
}
:host ::ng-deep .mat-radio-inner-circle{
border-radius:2px;
background-color: transparent!important;
border-bottom: 4px solid white;
border-right:4px solid white;
height:30px;
width:15px;
margin-top: -8px;
margin-left: 3px;
}
:host ::ng-deep .mat-radio-checked .mat-radio-outer-circle{
background:#ff4081!important;
}
:host ::ng-deep .mat-radio-checked .mat-radio-inner-circle{
transform: rotate(45deg) scale(0.5);
}
:host ::ng-deep .mat-radio-button .mat-radio-ripple{
height: 20px; /*double of your required circle radius*/
width: 20px; /*double of your required circle radius*/
left: calc(50% - 10px); /*'10px'-same as your required circle radius*/
top: calc(50% - 10px); /*'10px'-same as your required circle radius */
}

- 261
- 2
- 8
This is an easy solution though not the perfect one but it will get your job done!
change() {
if (this.formGroup.get('control1').value === true) {
this.formGroup.get('control2').setValue(false);
} else if (this.formGroup.get('control2').value === true){
this.formGroup.get('control1').setValue(false);
}
}
<mat-checkbox [formControlName]="'control1'" color="primary" (change)="change()">
control1
</mat-checkbox>
<mat-checkbox color="primary" [formControlName]="'control2'" (change)="change()">
control2
</mat-checkbox>

- 1
- 1