Skip to content

Commit 5592404

Browse files
crisbetotinayuangao
authored andcommitted
fix(select): support using shift + arrow key to toggle items in a multi-select (#9037)
Based on the accessibility guidelines for a multi-selection listbox (https://www.w3.org/TR/wai-aria-practices-1.1/#Listbox), potentially we can support toggling the previous/next item if the user presses shift + up/down arrow.
1 parent ec959e8 commit 5592404

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

src/lib/select/select.spec.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,68 @@ describe('MatSelect', () => {
435435
.toBe(false, 'Expected panel to stay closed.');
436436
}));
437437

438+
it('should toggle the next option when pressing shift + DOWN_ARROW on a multi-select',
439+
fakeAsync(() => {
440+
fixture.destroy();
441+
442+
const multiFixture = TestBed.createComponent(MultiSelect);
443+
const event = createKeyboardEvent('keydown', DOWN_ARROW);
444+
Object.defineProperty(event, 'shiftKey', {get: () => true});
445+
446+
multiFixture.detectChanges();
447+
select = multiFixture.debugElement.query(By.css('mat-select')).nativeElement;
448+
449+
multiFixture.componentInstance.select.open();
450+
multiFixture.detectChanges();
451+
flush();
452+
453+
expect(multiFixture.componentInstance.select.value).toBeFalsy();
454+
455+
dispatchEvent(select, event);
456+
multiFixture.detectChanges();
457+
458+
expect(multiFixture.componentInstance.select.value).toEqual(['pizza-1']);
459+
460+
dispatchEvent(select, event);
461+
multiFixture.detectChanges();
462+
463+
expect(multiFixture.componentInstance.select.value).toEqual(['pizza-1', 'tacos-2']);
464+
}));
465+
466+
it('should toggle the previous option when pressing shift + UP_ARROW on a multi-select',
467+
fakeAsync(() => {
468+
fixture.destroy();
469+
470+
const multiFixture = TestBed.createComponent(MultiSelect);
471+
const event = createKeyboardEvent('keydown', UP_ARROW);
472+
Object.defineProperty(event, 'shiftKey', {get: () => true});
473+
474+
multiFixture.detectChanges();
475+
select = multiFixture.debugElement.query(By.css('mat-select')).nativeElement;
476+
477+
multiFixture.componentInstance.select.open();
478+
multiFixture.detectChanges();
479+
flush();
480+
481+
// Move focus down first.
482+
for (let i = 0; i < 5; i++) {
483+
dispatchKeyboardEvent(select, 'keydown', DOWN_ARROW);
484+
multiFixture.detectChanges();
485+
}
486+
487+
expect(multiFixture.componentInstance.select.value).toBeFalsy();
488+
489+
dispatchEvent(select, event);
490+
multiFixture.detectChanges();
491+
492+
expect(multiFixture.componentInstance.select.value).toEqual(['chips-4']);
493+
494+
dispatchEvent(select, event);
495+
multiFixture.detectChanges();
496+
497+
expect(multiFixture.componentInstance.select.value).toEqual(['sandwich-3', 'chips-4']);
498+
}));
499+
438500
it('should prevent the default action when pressing space', fakeAsync(() => {
439501
const event = dispatchKeyboardEvent(select, 'keydown', SPACE);
440502
expect(event.defaultPrevented).toBe(true);

src/lib/select/select.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,15 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
665665
event.preventDefault();
666666
this._keyManager.activeItem._selectViaInteraction();
667667
} else {
668+
const isArrowKey = keyCode === DOWN_ARROW || keyCode === UP_ARROW;
669+
const previouslyFocusedIndex = this._keyManager.activeItemIndex;
670+
668671
this._keyManager.onKeydown(event);
672+
673+
if (this._multiple && isArrowKey && event.shiftKey && this._keyManager.activeItem &&
674+
this._keyManager.activeItemIndex !== previouslyFocusedIndex) {
675+
this._keyManager.activeItem._selectViaInteraction();
676+
}
669677
}
670678
}
671679

0 commit comments

Comments
 (0)