Skip to content

Commit

Permalink
fix(material/tabs): stop scrolling on tab change (#22265)
Browse files Browse the repository at this point in the history
* fix(material/tabs): stop scrolling on tab change

Adds min-height to the mat-tab-group wrapper, so page height is preserved
as tabs change, and page doesn't scroll up.

Fixes #9592

* fix(material/tabs): stop scrolling on tab change

Adds min-height to the mat-tab-group wrapper, so page height is preserved
as tabs change, and page doesn't scroll up.

Fixes #9592

* fix(material/tabs): stop scrolling on tab change …

Adds min-height to the mat-tab-group wrapper, so page height is preserved
as tabs change, and page doesn't scroll up.

Fixes #9592

(cherry picked from commit c12f168)
  • Loading branch information
ukrukarg authored and andrewseguin committed Apr 27, 2021
1 parent 9bb7b0c commit 7f556b5
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 0 deletions.
61 changes: 61 additions & 0 deletions src/material-experimental/mdc-tabs/tab-group.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ describe('MDC-based MatTabGroup', () => {
TabGroupWithIsActiveBinding,
NestedTabs,
TabGroupWithIndirectDescendantTabs,
TabGroupWithSpaceAbove,
],
});

Expand Down Expand Up @@ -665,6 +666,45 @@ describe('MDC-based MatTabGroup', () => {
}));
});

describe('tall tabs', () => {
beforeEach(() => {
window.scrollTo({top: 0});
});

it('should not scroll when changing tabs by clicking', fakeAsync(() => {
const fixture = TestBed.createComponent(TabGroupWithSpaceAbove);
fixture.detectChanges();
tick();
fixture.detectChanges();

window.scrollBy(0, 250);
expect(window.scrollY).toBe(250);

// select the second tab
let tabLabel = fixture.debugElement.queryAll(By.css('.mat-mdc-tab'))[1];
tabLabel.nativeElement.click();
checkSelectedIndex(1, fixture);

expect(window.scrollY).toBe(250);
tick();
}));

it('should not scroll when changing tabs programatically', fakeAsync(() => {
const fixture = TestBed.createComponent(TabGroupWithSpaceAbove);
fixture.detectChanges();
tick();
fixture.detectChanges();

window.scrollBy(0, 250);
expect(window.scrollY).toBe(250);

fixture.componentInstance.tabGroup.selectedIndex = 1;
fixture.detectChanges();

expect(window.scrollY).toBe(250);
tick();
}));
});

/**
* Checks that the `selectedIndex` has been updated; checks that the label and body have their
Expand Down Expand Up @@ -1067,3 +1107,24 @@ class TabGroupWithIndirectDescendantTabs {
class TabGroupWithInkBarFitToContent {
fitInkBarToContent = true;
}

@Component({
template: `
<div style="height: 300px; background-color: aqua">
Top Content here
</div>
<mat-tab-group>
<ng-container>
<mat-tab label="One">
<div style="height: 3000px; background-color: red"></div>
</mat-tab>
<mat-tab label="Two">
<div style="height: 3000px; background-color: green"></div>
</mat-tab>
</ng-container>
</mat-tab-group>
`,
})
class TabGroupWithSpaceAbove {
@ViewChild(MatTabGroup) tabGroup: MatTabGroup;
}
62 changes: 62 additions & 0 deletions src/material/tabs/tab-group.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ describe('MatTabGroup', () => {
TabGroupWithIsActiveBinding,
NestedTabs,
TabGroupWithIndirectDescendantTabs,
TabGroupWithSpaceAbove,
],
});

Expand Down Expand Up @@ -664,6 +665,46 @@ describe('MatTabGroup', () => {
}));
});

describe('tall tabs', () => {
beforeEach(() => {
window.scrollTo({top: 0});
});

it('should not scroll when changing tabs by clicking', fakeAsync(() => {
const fixture = TestBed.createComponent(TabGroupWithSpaceAbove);
fixture.detectChanges();
tick();
fixture.detectChanges();

window.scrollBy(0, 250);
expect(window.scrollY).toBe(250);

// select the second tab
let tabLabel = fixture.debugElement.queryAll(By.css('.mat-tab-label'))[1];
tabLabel.nativeElement.click();
checkSelectedIndex(1, fixture);

expect(window.scrollY).toBe(250);
tick();
}));

it('should not scroll when changing tabs programatically', fakeAsync(() => {
const fixture = TestBed.createComponent(TabGroupWithSpaceAbove);
fixture.detectChanges();
tick();
fixture.detectChanges();

window.scrollBy(0, 250);
expect(window.scrollY).toBe(250);

fixture.componentInstance.tabGroup.selectedIndex = 1;
fixture.detectChanges();

expect(window.scrollY).toBe(250);
tick();
}));
});

/**
* Checks that the `selectedIndex` has been updated; checks that the label and body have their
* respective `active` classes
Expand Down Expand Up @@ -998,3 +1039,24 @@ class TabsWithCustomAnimationDuration {}
class TabGroupWithIndirectDescendantTabs {
@ViewChild(MatTabGroup) tabGroup: MatTabGroup;
}

@Component({
template: `
<div style="height: 300px; background-color: aqua">
Top Content here
</div>
<mat-tab-group>
<ng-container>
<mat-tab label="One">
<div style="height: 3000px; background-color: red"></div>
</mat-tab>
<mat-tab label="Two">
<div style="height: 3000px; background-color: green"></div>
</mat-tab>
</ng-container>
</mat-tab-group>
`,
})
class TabGroupWithSpaceAbove {
@ViewChild(MatTabGroup) tabGroup: MatTabGroup;
}
7 changes: 7 additions & 0 deletions src/material/tabs/tab-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,10 @@ export abstract class _MatTabGroupBase extends _MatTabGroupMixinBase implements

if (!isFirstRun) {
this.selectedTabChange.emit(this._createChangeEvent(indexToSelect));
// Preserve the height so page doesn't scroll up during tab change.
// Fixes https://stackblitz.com/edit/mat-tabs-scroll-page-top-on-tab-change
const wrapper = this._tabBodyWrapper.nativeElement;
wrapper.style.minHeight = wrapper.clientHeight + 'px';
}

// Changing these values after change detection has run
Expand All @@ -211,6 +215,9 @@ export abstract class _MatTabGroupBase extends _MatTabGroupMixinBase implements

if (!isFirstRun) {
this.selectedIndexChange.emit(indexToSelect);
// Clear the min-height, this was needed during tab change to avoid
// unnecessary scrolling.
this._tabBodyWrapper.nativeElement.style.minHeight = '';
}
});
}
Expand Down

0 comments on commit 7f556b5

Please sign in to comment.