Skip to content

Commit 666e9b3

Browse files
crisbetoandrewseguin
authored andcommitted
fix(sidenav): focus trap enabled state not updated if mode changes while open (#16602)
Currently we update the focus trap enabled state only on open/close, however this means that it'll be incorrect if the sidenav mode changes while it's open. Fixes #16601. (cherry picked from commit 197091c)
1 parent f590dc6 commit 666e9b3

File tree

2 files changed

+31
-4
lines changed

2 files changed

+31
-4
lines changed

src/material/sidenav/drawer.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,27 @@ describe('MatDrawer', () => {
510510
expect(document.activeElement).not.toBe(firstFocusableElement);
511511
}));
512512

513+
it('should update the focus trap enable state if the mode changes while open', fakeAsync(() => {
514+
testComponent.mode = 'side';
515+
fixture.detectChanges();
516+
517+
drawer.open();
518+
fixture.detectChanges();
519+
tick();
520+
521+
const anchors =
522+
Array.from<HTMLElement>(fixture.nativeElement.querySelectorAll('.cdk-focus-trap-anchor'));
523+
524+
expect(anchors.every(anchor => !anchor.hasAttribute('tabindex')))
525+
.toBe(true, 'Expected focus trap anchors to be disabled in side mode.');
526+
527+
testComponent.mode = 'over';
528+
fixture.detectChanges();
529+
530+
expect(anchors.every(anchor => anchor.getAttribute('tabindex') === '0'))
531+
.toBe(true, 'Expected focus trap anchors to be enabled in over mode.');
532+
}));
533+
513534
});
514535
});
515536

src/material/sidenav/drawer.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
154154
get mode(): 'over' | 'push' | 'side' { return this._mode; }
155155
set mode(value: 'over' | 'push' | 'side') {
156156
this._mode = value;
157+
this._updateFocusTrapState();
157158
this._modeChanged.next();
158159
}
159160
private _mode: 'over' | 'push' | 'side' = 'over';
@@ -333,7 +334,7 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
333334

334335
ngAfterContentInit() {
335336
this._focusTrap = this._focusTrapFactory.create(this._elementRef.nativeElement);
336-
this._focusTrap.enabled = this._isFocusTrapEnabled;
337+
this._updateFocusTrapState();
337338
}
338339

339340
ngAfterContentChecked() {
@@ -400,9 +401,7 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
400401
this._restoreFocus();
401402
}
402403

403-
if (this._focusTrap) {
404-
this._focusTrap.enabled = this._isFocusTrapEnabled;
405-
}
404+
this._updateFocusTrapState();
406405

407406
return new Promise<MatDrawerToggleResult>(resolve => {
408407
this.openedChange.pipe(take(1)).subscribe(open => resolve(open ? 'open' : 'close'));
@@ -413,6 +412,13 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
413412
return this._elementRef.nativeElement ? (this._elementRef.nativeElement.offsetWidth || 0) : 0;
414413
}
415414

415+
/** Updates the enabled state of the focus trap. */
416+
private _updateFocusTrapState() {
417+
if (this._focusTrap) {
418+
this._focusTrap.enabled = this._isFocusTrapEnabled;
419+
}
420+
}
421+
416422
// We have to use a `HostListener` here in order to support both Ivy and ViewEngine.
417423
// In Ivy the `host` bindings will be merged when this class is extended, whereas in
418424
// ViewEngine they're overwritte.

0 commit comments

Comments
 (0)