diff --git a/src/material/expansion/expansion-panel.scss b/src/material/expansion/expansion-panel.scss
index 7af49c54126b..fdd020424de5 100644
--- a/src/material/expansion/expansion-panel.scss
+++ b/src/material/expansion/expansion-panel.scss
@@ -62,6 +62,10 @@
}
}
+.mat-expansion-panel-hidden {
+ height: 0;
+}
+
.mat-expansion-panel-body {
padding: 0 24px 16px;
}
diff --git a/src/material/expansion/expansion-panel.ts b/src/material/expansion/expansion-panel.ts
index 539366df4f7f..50446966345f 100644
--- a/src/material/expansion/expansion-panel.ts
+++ b/src/material/expansion/expansion-panel.ts
@@ -95,6 +95,7 @@ export const MAT_EXPANSION_PANEL_DEFAULT_OPTIONS =
'[class.mat-expanded]': 'expanded',
'[class._mat-animation-noopable]': '_animationMode === "NoopAnimations"',
'[class.mat-expansion-panel-spacing]': '_hasSpacing()',
+ '[@.disabled]': '_animationsDisabled',
},
})
export class MatExpansionPanel
@@ -150,6 +151,12 @@ export class MatExpansionPanel
/** Stream of body animation done events. */
readonly _bodyAnimationDone = new Subject
();
+ /** Whether Angular animations in the panel body should be disabled. */
+ _animationsDisabled = false;
+
+ /** Whether panel body should be hidden. */
+ _panelHidden = false;
+
constructor(
@Optional() @SkipSelf() @Inject(MAT_ACCORDION) accordion: MatAccordionBase,
_changeDetectorRef: ChangeDetectorRef,
@@ -218,6 +225,9 @@ export class MatExpansionPanel
ngAfterContentInit() {
if (this._lazyContent && this._lazyContent._expansionPanel === this) {
+ this._panelHidden = !this.expanded;
+ this._animationsDisabled = !this.expanded;
+
// Render the content as soon as the panel becomes open.
this.opened
.pipe(
@@ -227,6 +237,7 @@ export class MatExpansionPanel
)
.subscribe(() => {
this._portal = new TemplatePortal(this._lazyContent._template, this._viewContainerRef);
+ this._hidePanel();
});
}
}
@@ -251,6 +262,31 @@ export class MatExpansionPanel
return false;
}
+
+ _animationStarted() {
+ // Currently the `bodyExpansion` animation has a `void => collapsed` transition which is
+ // there to work around a bug in Angular (see #13088), however this introduces a different
+ // issue. The new transition will cause to flicker in certain situations (see #22715), if the
+ // consumer has set a inner lazy-loaded expansion panel's header height that is different from the
+ // default one.
+ // Part of work around is to disable animations on the body and re-enabling them after the first animation has run.
+ // Ideally this wouldn't be necessary if we remove the `void => collapsed` transition, but we have
+ // to wait for https://github.com/angular/angular/issues/18847 to be resolved.
+ this._animationsDisabled = false;
+ }
+
+ private _hidePanel(): void {
+ // Currently the `bodyExpansion` animation has a `void => collapsed` transition which is
+ // there to work around a bug in Angular (see #13088), however this introduces a different
+ // issue. The new transition will cause to flicker in certain situations (see #22715), if the
+ // consumer has set a inner lazy-loaded expansion panel's header height that is different from the
+ // default one.
+ // Part of work around is to set non-expanded panel's height to 0px with class on init
+ // so that outer expansion panel can calculate height of its body properly.
+ // Ideally this wouldn't be necessary if we remove the `void => collapsed` transition, but we have
+ // to wait for https://github.com/angular/angular/issues/18847 to be resolved.
+ this._panelHidden = false;
+ }
}
/**
diff --git a/tools/public_api_guard/material/expansion.md b/tools/public_api_guard/material/expansion.md
index 0782491f8e1e..0a206494a9c3 100644
--- a/tools/public_api_guard/material/expansion.md
+++ b/tools/public_api_guard/material/expansion.md
@@ -107,6 +107,9 @@ export class MatExpansionPanel extends CdkAccordionItem implements AfterContentI
readonly afterExpand: EventEmitter;
// (undocumented)
_animationMode: string;
+ _animationsDisabled: boolean;
+ // (undocumented)
+ _animationStarted(): void;
_body: ElementRef;
readonly _bodyAnimationDone: Subject;
close(): void;
@@ -125,6 +128,7 @@ export class MatExpansionPanel extends CdkAccordionItem implements AfterContentI
// (undocumented)
ngOnDestroy(): void;
open(): void;
+ _panelHidden: boolean;
_portal: TemplatePortal;
toggle(): void;
get togglePosition(): MatAccordionTogglePosition;