@@ -283,7 +283,7 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
283283 }
284284
285285 this . _takeFocus ( ) ;
286- } else {
286+ } else if ( this . _isFocusWithinDrawer ( ) ) {
287287 this . _restoreFocus ( ) ;
288288 }
289289 } ) ;
@@ -339,29 +339,31 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
339339 }
340340
341341 /**
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 .
344344 */
345345 private _restoreFocus ( ) {
346346 if ( ! this . autoFocus ) {
347347 return ;
348348 }
349349
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 ( ) ;
359355 }
360356
361357 this . _elementFocusedBeforeDrawerWasOpened = null ;
362358 this . _openedVia = null ;
363359 }
364360
361+ /** Whether focus is currently within the drawer. */
362+ private _isFocusWithinDrawer ( ) : boolean {
363+ const activeEl = this . _doc ?. activeElement ;
364+ return ! ! activeEl && this . _elementRef . nativeElement . contains ( activeEl ) ;
365+ }
366+
365367 ngAfterContentInit ( ) {
366368 this . _focusTrap = this . _focusTrapFactory . create ( this . _elementRef . nativeElement ) ;
367369 this . _updateFocusTrapState ( ) ;
@@ -403,23 +405,47 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
403405 return this . toggle ( false ) ;
404406 }
405407
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+
406416 /**
407417 * Toggle this drawer.
408418 * @param isOpen Whether the drawer should be open.
409419 * @param openedVia Whether the drawer was opened by a key press, mouse click or programmatically.
410420 * Used for focus management after the sidenav is closed.
411421 */
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+ }
414429
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 > {
415439 this . _opened = isOpen ;
416440
417441 if ( isOpen ) {
418442 this . _animationState = this . _enableAnimations ? 'open' : 'open-instant' ;
419443 this . _openedVia = openedVia ;
420444 } else {
421445 this . _animationState = 'void' ;
422- this . _restoreFocus ( ) ;
446+ if ( restoreFocus ) {
447+ this . _restoreFocus ( ) ;
448+ }
423449 }
424450
425451 this . _updateFocusTrapState ( ) ;
@@ -818,14 +844,14 @@ export class MatDrawerContainer implements AfterContentInit, DoCheck, OnDestroy
818844
819845 _onBackdropClicked ( ) {
820846 this . backdropClick . emit ( ) ;
821- this . _closeModalDrawer ( ) ;
847+ this . _closeModalDrawersViaBackdrop ( ) ;
822848 }
823849
824- _closeModalDrawer ( ) {
850+ _closeModalDrawersViaBackdrop ( ) {
825851 // Close all open drawers where closing is not disabled and the mode is not `side`.
826852 [ this . _start , this . _end ]
827853 . filter ( drawer => drawer && ! drawer . disableClose && this . _canHaveBackdrop ( drawer ) )
828- . forEach ( drawer => drawer ! . close ( ) ) ;
854+ . forEach ( drawer => drawer ! . _closeViaBackdropClick ( ) ) ;
829855 }
830856
831857 _isShowingBackdrop ( ) : boolean {
0 commit comments