@@ -148,30 +148,31 @@ export class MatDialogContainer extends BasePortalOutlet {
148148 return this . _portalOutlet . attachDomPortal ( portal ) ;
149149 }
150150
151- /** Moves the focus inside the focus trap. */
152- private _trapFocus ( ) {
153- const element = this . _elementRef . nativeElement ;
151+ /** Moves focus back into the dialog if it was moved out. */
152+ _recaptureFocus ( ) {
153+ if ( ! this . _containsFocus ( ) ) {
154+ const focusWasTrapped = this . _getFocusTrap ( ) . focusInitialElement ( ) ;
154155
155- if ( ! this . _focusTrap ) {
156- this . _focusTrap = this . _focusTrapFactory . create ( element ) ;
156+ if ( ! focusWasTrapped ) {
157+ this . _elementRef . nativeElement . focus ( ) ;
158+ }
157159 }
160+ }
158161
162+ /** Moves the focus inside the focus trap. */
163+ private _trapFocus ( ) {
159164 // If we were to attempt to focus immediately, then the content of the dialog would not yet be
160165 // ready in instances where change detection has to run first. To deal with this, we simply
161166 // wait for the microtask queue to be empty.
162167 if ( this . _config . autoFocus ) {
163- this . _focusTrap . focusInitialElementWhenReady ( ) ;
164- } else {
165- const activeElement = this . _document . activeElement ;
166-
168+ this . _getFocusTrap ( ) . focusInitialElementWhenReady ( ) ;
169+ } else if ( ! this . _containsFocus ( ) ) {
167170 // Otherwise ensure that focus is on the dialog container. It's possible that a different
168171 // component tried to move focus while the open animation was running. See:
169172 // https://github.com/angular/components/issues/16215. Note that we only want to do this
170173 // if the focus isn't inside the dialog already, because it's possible that the consumer
171174 // turned off `autoFocus` in order to move focus themselves.
172- if ( activeElement !== element && ! element . contains ( activeElement ) ) {
173- element . focus ( ) ;
174- }
175+ this . _elementRef . nativeElement . focus ( ) ;
175176 }
176177 }
177178
@@ -214,6 +215,22 @@ export class MatDialogContainer extends BasePortalOutlet {
214215 }
215216 }
216217
218+ /** Returns whether focus is inside the dialog. */
219+ private _containsFocus ( ) {
220+ const element = this . _elementRef . nativeElement ;
221+ const activeElement = this . _document . activeElement ;
222+ return element === activeElement || element . contains ( activeElement ) ;
223+ }
224+
225+ /** Gets the focus trap associated with the dialog. */
226+ private _getFocusTrap ( ) {
227+ if ( ! this . _focusTrap ) {
228+ this . _focusTrap = this . _focusTrapFactory . create ( this . _elementRef . nativeElement ) ;
229+ }
230+
231+ return this . _focusTrap ;
232+ }
233+
217234 /** Callback, invoked whenever an animation on the host completes. */
218235 _onAnimationDone ( event : AnimationEvent ) {
219236 if ( event . toState === 'enter' ) {
0 commit comments