From 1a1dff849ed2c05728bb061316eb1273cc6e1727 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 27 Mar 2026 19:17:58 +0100 Subject: [PATCH] fix(material/sidenav): not resetting margin if transition does not start Currently the sidenav sets its margin when the transition starts, however that might not happen if its interruped which can leave it in a broken state. These changes switch to always dispatching the event. Fixes #32992. --- src/material/sidenav/drawer.ts | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/material/sidenav/drawer.ts b/src/material/sidenav/drawer.ts index 43e394bb5a35..455d0693669e 100644 --- a/src/material/sidenav/drawer.ts +++ b/src/material/sidenav/drawer.ts @@ -364,7 +364,6 @@ export class MatDrawer implements AfterViewInit, OnDestroy { }); } }), - renderer.listen(element, 'transitionrun', this._handleTransitionEvent), renderer.listen(element, 'transitionend', this._handleTransitionEvent), renderer.listen(element, 'transitioncancel', this._handleTransitionEvent), ]; @@ -572,6 +571,11 @@ export class MatDrawer implements AfterViewInit, OnDestroy { // Note: it's important to set this as early as possible, // otherwise the animation can look glitchy in some cases. this._setIsAnimating(true); + + // Previously we dispatched this in a `transitionrun` event, but it might not fire + // if the element is hidden (see #32992). Since this event is load-bearing for the + // margin calculations, we need it to fire consistently. + setTimeout(() => this._animationStarted.next()); } else { // Simulate the animation events if animations are disabled. setTimeout(() => { @@ -646,17 +650,13 @@ export class MatDrawer implements AfterViewInit, OnDestroy { if (event.target === element) { this._ngZone.run(() => { - if (event.type === 'transitionrun') { - this._animationStarted.next(event); - } else { - // Don't toggle the animating state on `transitioncancel` since another animation should - // start afterwards. This prevents the drawer from blinking if an animation is interrupted. - if (event.type === 'transitionend') { - this._setIsAnimating(false); - } - - this._animationEnd.next(event); + // Don't toggle the animating state on `transitioncancel` since another animation should + // start afterwards. This prevents the drawer from blinking if an animation is interrupted. + if (event.type === 'transitionend') { + this._setIsAnimating(false); } + + this._animationEnd.next(event); }); } }; @@ -941,6 +941,7 @@ export class MatDrawerContainer implements AfterContentInit, DoCheck, OnDestroy * is properly hidden. */ private _watchDrawerToggle(drawer: MatDrawer): void { + // drawer._animationStarted.pipe(takeUntil(this._drawers.changes)).subscribe(() => { this.updateContentMargins(); this._changeDetectorRef.markForCheck();