diff --git a/src/lib/expansion/expansion-panel.html b/src/lib/expansion/expansion-panel.html
index de6e62ed0000..7b1f7ccdc645 100644
--- a/src/lib/expansion/expansion-panel.html
+++ b/src/lib/expansion/expansion-panel.html
@@ -1,10 +1,13 @@
+ #body>
diff --git a/src/lib/expansion/expansion-panel.scss b/src/lib/expansion/expansion-panel.scss
index c242181478ee..5dd26f80b2ab 100644
--- a/src/lib/expansion/expansion-panel.scss
+++ b/src/lib/expansion/expansion-panel.scss
@@ -11,12 +11,10 @@
}
.mat-expansion-panel-content {
- .mat-expanded & {
- overflow: visible;
- }
+ overflow: hidden;
- &, &.ng-animating {
- overflow: hidden;
+ &.mat-expanded {
+ overflow: visible;
}
}
diff --git a/src/lib/expansion/expansion-panel.ts b/src/lib/expansion/expansion-panel.ts
index 45e8be1468ab..960e47270351 100644
--- a/src/lib/expansion/expansion-panel.ts
+++ b/src/lib/expansion/expansion-panel.ts
@@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
+import {AnimationEvent} from '@angular/animations';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
@@ -139,6 +140,22 @@ export class MatExpansionPanel extends CdkAccordionItem
super.ngOnDestroy();
this._inputChanges.complete();
}
+
+ _bodyAnimation(event: AnimationEvent) {
+ const classList = event.element.classList;
+ const cssClass = 'mat-expanded';
+ const {phaseName, toState} = event;
+
+ // Toggle the body's `overflow: hidden` class when closing starts or when expansion ends in
+ // order to prevent the cases where switching too early would cause the animation to jump.
+ // Note that we do it directly on the DOM element to avoid the slight delay that comes
+ // with doing it via change detection.
+ if (phaseName === 'done' && toState === 'expanded') {
+ classList.add(cssClass);
+ } else if (phaseName === 'start' && toState === 'collapsed') {
+ classList.remove(cssClass);
+ }
+ }
}
@Directive({
diff --git a/src/lib/expansion/expansion.spec.ts b/src/lib/expansion/expansion.spec.ts
index 29a279fa651f..f2017beaf9e9 100644
--- a/src/lib/expansion/expansion.spec.ts
+++ b/src/lib/expansion/expansion.spec.ts
@@ -1,4 +1,4 @@
-import {async, TestBed, fakeAsync, tick, ComponentFixture} from '@angular/core/testing';
+import {async, TestBed, fakeAsync, tick, ComponentFixture, flush} from '@angular/core/testing';
import {Component, ViewChild} from '@angular/core';
import {By} from '@angular/platform-browser';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
@@ -26,19 +26,22 @@ describe('MatExpansionPanel', () => {
TestBed.compileComponents();
}));
- it('should expand and collapse the panel', () => {
+ it('should expand and collapse the panel', fakeAsync(() => {
const fixture = TestBed.createComponent(PanelWithContent);
- const contentEl = fixture.debugElement.query(By.css('.mat-expansion-panel-content'));
- const headerEl = fixture.debugElement.query(By.css('.mat-expansion-panel-header'));
+ const contentEl = fixture.nativeElement.querySelector('.mat-expansion-panel-content');
+ const headerEl = fixture.nativeElement.querySelector('.mat-expansion-panel-header');
fixture.detectChanges();
- expect(headerEl.classes['mat-expanded']).toBeFalsy();
- expect(contentEl.classes['mat-expanded']).toBeFalsy();
+
+ expect(headerEl.classList).not.toContain('mat-expanded');
+ expect(contentEl.classList).not.toContain('mat-expanded');
fixture.componentInstance.expanded = true;
fixture.detectChanges();
- expect(headerEl.classes['mat-expanded']).toBeTruthy();
- expect(contentEl.classes['mat-expanded']).toBeTruthy();
- });
+ flush();
+
+ expect(headerEl.classList).toContain('mat-expanded');
+ expect(contentEl.classList).toContain('mat-expanded');
+ }));
it('should be able to render panel content lazily', fakeAsync(() => {
let fixture = TestBed.createComponent(LazyPanelWithContent);