Skip to content

Commit 9105a44

Browse files
authored
fix(material/list): make disabled selection list keyboard navigable (#33544)
* fix(material/list): make disabled selection list keyboard navigable Updates Angular Components Selection List component to be able to be navigated via keyboard when it is in a disabled state to improve accessibility. Fixes b/518820148 * refactor(material/list): fix lint errors Updates previous changes to remove nested ternary expression.
1 parent 0254d10 commit 9105a44

1 file changed

Lines changed: 26 additions & 8 deletions

File tree

‎src/material/list/selection-list.ts‎

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import {FocusKeyManager} from '@angular/cdk/a11y';
1010
import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion';
1111
import {SelectionModel} from '@angular/cdk/collections';
12-
import {A, ENTER, SPACE, hasModifierKey} from '@angular/cdk/keycodes';
12+
import {A, ENTER, SPACE, DOWN_ARROW, UP_ARROW, hasModifierKey} from '@angular/cdk/keycodes';
1313
import {_getFocusedElementPierceShadowDom} from '@angular/cdk/platform';
1414
import {
1515
AfterViewInit,
@@ -365,6 +365,18 @@ export class MatSelectionList
365365
_handleKeydown(event: KeyboardEvent) {
366366
const activeItem = this._keyManager.activeItem;
367367

368+
if (activeItem && (event.keyCode === DOWN_ARROW || event.keyCode === UP_ARROW)) {
369+
const focusedElement = _getFocusedElementPierceShadowDom();
370+
const isOptionFocused = this._items
371+
.toArray()
372+
.some(item => item._elementRef.nativeElement === focusedElement);
373+
if (!isOptionFocused) {
374+
event.preventDefault();
375+
activeItem.focus();
376+
return;
377+
}
378+
}
379+
368380
if (
369381
(event.keyCode === ENTER || event.keyCode === SPACE) &&
370382
!this._keyManager.isTyping() &&
@@ -399,10 +411,6 @@ export class MatSelectionList
399411

400412
/** Handles focusin events within the list. */
401413
private _handleFocusin = (event: FocusEvent) => {
402-
if (this.disabled) {
403-
return;
404-
}
405-
406414
const activeIndex = this._items
407415
.toArray()
408416
.findIndex(item => item._elementRef.nativeElement.contains(event.target as HTMLElement));
@@ -432,7 +440,7 @@ export class MatSelectionList
432440
.withHomeAndEnd()
433441
.withTypeAhead()
434442
.withWrap()
435-
.skipPredicate(() => this.disabled);
443+
.skipPredicate(() => false);
436444

437445
// Set the initial focus.
438446
this._resetActiveOption();
@@ -455,7 +463,15 @@ export class MatSelectionList
455463
* @param index Index of the active option. If set to -1, no option will be active.
456464
*/
457465
private _setActiveOption(index: number) {
458-
this._items.forEach((item, itemIndex) => item._setTabindex(itemIndex === index ? 0 : -1));
466+
this._items.forEach((item, itemIndex) => {
467+
let tabindex = -1;
468+
469+
if (!this.disabled && itemIndex === index) {
470+
tabindex = 0;
471+
}
472+
473+
item._setTabindex(tabindex);
474+
});
459475
this._keyManager.updateActiveItem(index);
460476
}
461477

@@ -465,7 +481,9 @@ export class MatSelectionList
465481
*/
466482
private _resetActiveOption() {
467483
if (this.disabled) {
468-
this._setActiveOption(-1);
484+
const activeItem = this._items.find(item => item.selected) || this._items.first;
485+
const index = activeItem ? this._items.toArray().indexOf(activeItem) : -1;
486+
this._setActiveOption(index);
469487
return;
470488
}
471489

0 commit comments

Comments
 (0)