@@ -99,12 +99,29 @@ export const MAT_DRAWER_CONTAINER = new InjectionToken<MatDrawerContainer>('MAT_
9999export class MatDrawerContent extends CdkScrollable implements AfterContentInit {
100100 private _platform = inject ( Platform ) ;
101101 private _changeDetectorRef = inject ( ChangeDetectorRef ) ;
102+ private _element = inject < ElementRef < HTMLElement > > ( ElementRef ) ;
103+ private _isInert = false ;
102104 _container = inject ( MatDrawerContainer ) ;
103105
104106 ngAfterContentInit ( ) {
105- this . _container . _contentMarginChanges . subscribe ( ( ) => {
106- this . _changeDetectorRef . markForCheck ( ) ;
107- } ) ;
107+ this . _container . _contentMarginChanges . subscribe ( ( ) => this . _changeDetectorRef . markForCheck ( ) ) ;
108+ }
109+
110+ _updateInert ( ) {
111+ const newValue = this . _container . _isShowingBackdrop ( ) ;
112+
113+ if ( newValue !== this . _isInert ) {
114+ const element = this . _element . nativeElement ;
115+ this . _isInert = newValue ;
116+
117+ // This can be called right before we attempt to move focus. Set the value
118+ // directly, instead of waiting on change detection, because the timing is tight.
119+ if ( newValue ) {
120+ element . setAttribute ( 'inert' , 'true' ) ;
121+ } else {
122+ element . removeAttribute ( 'inert' ) ;
123+ }
124+ }
108125 }
109126
110127 /** Determines whether the content element should be hidden from the user. */
@@ -360,11 +377,18 @@ export class MatDrawer implements AfterViewInit, OnDestroy {
360377 }
361378
362379 /**
363- * Focuses the provided element. If the element is not focusable, it will add a tabIndex
364- * attribute to forcefully focus it. The attribute is removed after focus is moved.
365- * @param element The element to focus.
380+ * Focuses the first element that matches the given selector within the focus trap.
381+ * @param selector The CSS selector for the element to set focus to.
366382 */
367- private _forceFocus ( element : HTMLElement , options ?: FocusOptions ) {
383+ private _focusByCssSelector ( selector : string , options ?: FocusOptions ) {
384+ const element = this . _elementRef . nativeElement . querySelector ( selector ) as HTMLElement | null ;
385+
386+ if ( ! element ) {
387+ return ;
388+ }
389+
390+ // If the element isn't focusable, force focus to it by
391+ // setting a tabindex, focusing it and then clear it.
368392 if ( ! this . _interactivityChecker . isFocusable ( element ) ) {
369393 element . tabIndex = - 1 ;
370394 // The tabindex attribute should be removed to avoid navigating to that element again
@@ -379,20 +403,8 @@ export class MatDrawer implements AfterViewInit, OnDestroy {
379403 const cleanupMousedown = this . _renderer . listen ( element , 'mousedown' , callback ) ;
380404 } ) ;
381405 }
382- element . focus ( options ) ;
383- }
384406
385- /**
386- * Focuses the first element that matches the given selector within the focus trap.
387- * @param selector The CSS selector for the element to set focus to.
388- */
389- private _focusByCssSelector ( selector : string , options ?: FocusOptions ) {
390- let elementToFocus = this . _elementRef . nativeElement . querySelector (
391- selector ,
392- ) as HTMLElement | null ;
393- if ( elementToFocus ) {
394- this . _forceFocus ( elementToFocus , options ) ;
395- }
407+ element . focus ( options ) ;
396408 }
397409
398410 /**
@@ -421,24 +433,38 @@ export class MatDrawer implements AfterViewInit, OnDestroy {
421433 if ( ! hasMovedFocus && typeof element . focus === 'function' ) {
422434 element . focus ( ) ;
423435 }
436+
437+ // When capturing focus, we need to delay making the
438+ // container inert until focus has actually been moved.
439+ this . _notifyContentFocus ( ) ;
424440 } ,
425441 { injector : this . _injector } ,
426442 ) ;
427443 break ;
428444 case 'first-heading' :
429445 this . _focusByCssSelector ( 'h1, h2, h3, h4, h5, h6, [role="heading"]' ) ;
446+ this . _notifyContentFocus ( ) ;
430447 break ;
431448 default :
432449 this . _focusByCssSelector ( this . autoFocus ! ) ;
450+ this . _notifyContentFocus ( ) ;
433451 break ;
434452 }
435453 }
436454
455+ private _notifyContentFocus ( ) {
456+ ( this . _container ?. _content || this . _container ?. _userContent ) ?. _updateInert ( ) ;
457+ }
458+
437459 /**
438460 * Restores focus to the element that was originally focused when the drawer opened.
439461 * If no element was focused at that time, the focus will be restored to the drawer.
440462 */
441463 private _restoreFocus ( focusOrigin : Exclude < FocusOrigin , null > ) {
464+ // When restoring focus, we need remove `inert` as early as possible,
465+ // because the element needs to become focusable before we can focus it.
466+ this . _notifyContentFocus ( ) ;
467+
442468 if ( this . autoFocus === 'dialog' ) {
443469 return ;
444470 }
@@ -923,7 +949,6 @@ export class MatDrawerContainer implements AfterContentInit, DoCheck, OnDestroy
923949 * is properly hidden.
924950 */
925951 private _watchDrawerToggle ( drawer : MatDrawer ) : void {
926- //
927952 drawer . _animationStarted . pipe ( takeUntil ( this . _drawers . changes ) ) . subscribe ( ( ) => {
928953 this . updateContentMargins ( ) ;
929954 this . _changeDetectorRef . markForCheck ( ) ;
0 commit comments