@@ -283,7 +283,7 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
283
283
}
284
284
285
285
this . _takeFocus ( ) ;
286
- } else {
286
+ } else if ( this . _isFocusWithinDrawer ( ) ) {
287
287
this . _restoreFocus ( ) ;
288
288
}
289
289
} ) ;
@@ -339,29 +339,31 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
339
339
}
340
340
341
341
/**
342
- * If focus is currently inside the drawer, restores it to where it was before the drawer
343
- * opened .
342
+ * Restores focus to the element that was originally focused when the drawer opened.
343
+ * If no element was focused at that time, the focus will be restored to the drawer .
344
344
*/
345
345
private _restoreFocus ( ) {
346
346
if ( ! this . autoFocus ) {
347
347
return ;
348
348
}
349
349
350
- const activeEl = this . _doc && this . _doc . activeElement ;
351
-
352
- if ( activeEl && this . _elementRef . nativeElement . contains ( activeEl ) ) {
353
- // Note that we don't check via `instanceof HTMLElement` so that we can cover SVGs as well.
354
- if ( this . _elementFocusedBeforeDrawerWasOpened ) {
355
- this . _focusMonitor . focusVia ( this . _elementFocusedBeforeDrawerWasOpened , this . _openedVia ) ;
356
- } else {
357
- this . _elementRef . nativeElement . blur ( ) ;
358
- }
350
+ // Note that we don't check via `instanceof HTMLElement` so that we can cover SVGs as well.
351
+ if ( this . _elementFocusedBeforeDrawerWasOpened ) {
352
+ this . _focusMonitor . focusVia ( this . _elementFocusedBeforeDrawerWasOpened , this . _openedVia ) ;
353
+ } else {
354
+ this . _elementRef . nativeElement . blur ( ) ;
359
355
}
360
356
361
357
this . _elementFocusedBeforeDrawerWasOpened = null ;
362
358
this . _openedVia = null ;
363
359
}
364
360
361
+ /** Whether focus is currently within the drawer. */
362
+ private _isFocusWithinDrawer ( ) : boolean {
363
+ const activeEl = this . _doc && this . _doc . activeElement ;
364
+ return activeEl && this . _elementRef . nativeElement . contains ( activeEl ) ;
365
+ }
366
+
365
367
ngAfterContentInit ( ) {
366
368
this . _focusTrap = this . _focusTrapFactory . create ( this . _elementRef . nativeElement ) ;
367
369
this . _updateFocusTrapState ( ) ;
@@ -403,23 +405,47 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
403
405
return this . toggle ( false ) ;
404
406
}
405
407
408
+ /** Closes the drawer with context that the backdrop was clicked. */
409
+ _closeViaBackdropClick ( ) : Promise < MatDrawerToggleResult > {
410
+ // If the drawer is closed upon a backdrop click, we always want to restore focus. We
411
+ // don't need to check whether focus is currently in the drawer, as clicking on the
412
+ // backdrop causes blurring of the active element.
413
+ return this . _setOpen ( /* isOpen */ false , /* restoreFocus */ true ) ;
414
+ }
415
+
406
416
/**
407
417
* Toggle this drawer.
408
418
* @param isOpen Whether the drawer should be open.
409
419
* @param openedVia Whether the drawer was opened by a key press, mouse click or programmatically.
410
420
* Used for focus management after the sidenav is closed.
411
421
*/
412
- toggle ( isOpen : boolean = ! this . opened , openedVia : FocusOrigin = 'program' ) :
413
- Promise < MatDrawerToggleResult > {
422
+ toggle ( isOpen : boolean = ! this . opened , openedVia ?: FocusOrigin )
423
+ : Promise < MatDrawerToggleResult > {
424
+ // If the focus is currently inside the drawer content and we are closing the drawer,
425
+ // restore the focus to the initially focused element (when the drawer opened).
426
+ return this . _setOpen (
427
+ isOpen , /* restoreFocus */ ! isOpen && this . _isFocusWithinDrawer ( ) , openedVia ) ;
428
+ }
414
429
430
+ /**
431
+ * Toggles the opened state of the drawer.
432
+ * @param isOpen Whether the drawer should open or close.
433
+ * @param restoreFocus Whether focus should be restored on close.
434
+ * @param openedVia Focus origin that can be optionally set when opening a drawer. The
435
+ * origin will be used later when focus is restored on drawer close.
436
+ */
437
+ private _setOpen ( isOpen : boolean , restoreFocus : boolean , openedVia : FocusOrigin = 'program' )
438
+ : Promise < MatDrawerToggleResult > {
415
439
this . _opened = isOpen ;
416
440
417
441
if ( isOpen ) {
418
442
this . _animationState = this . _enableAnimations ? 'open' : 'open-instant' ;
419
443
this . _openedVia = openedVia ;
420
444
} else {
421
445
this . _animationState = 'void' ;
422
- this . _restoreFocus ( ) ;
446
+ if ( restoreFocus ) {
447
+ this . _restoreFocus ( ) ;
448
+ }
423
449
}
424
450
425
451
this . _updateFocusTrapState ( ) ;
@@ -818,14 +844,14 @@ export class MatDrawerContainer implements AfterContentInit, DoCheck, OnDestroy
818
844
819
845
_onBackdropClicked ( ) {
820
846
this . backdropClick . emit ( ) ;
821
- this . _closeModalDrawer ( ) ;
847
+ this . _closeModalDrawersViaBackdrop ( ) ;
822
848
}
823
849
824
- _closeModalDrawer ( ) {
850
+ _closeModalDrawersViaBackdrop ( ) {
825
851
// Close all open drawers where closing is not disabled and the mode is not `side`.
826
852
[ this . _start , this . _end ]
827
853
. filter ( drawer => drawer && ! drawer . disableClose && this . _canHaveBackdrop ( drawer ) )
828
- . forEach ( drawer => drawer ! . close ( ) ) ;
854
+ . forEach ( drawer => drawer ! . _closeViaBackdropClick ( ) ) ;
829
855
}
830
856
831
857
_isShowingBackdrop ( ) : boolean {
0 commit comments