Skip to content

Commit 5ecefa7

Browse files
ukrukargandrewseguin
authored andcommitted
fix(material/tabs): stop scrolling on tab change (#22265)
* 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)
1 parent 7230764 commit 5ecefa7

File tree

3 files changed

+130
-0
lines changed

3 files changed

+130
-0
lines changed

src/material-experimental/mdc-tabs/tab-group.spec.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ describe('MDC-based MatTabGroup', () => {
3939
TabGroupWithIsActiveBinding,
4040
NestedTabs,
4141
TabGroupWithIndirectDescendantTabs,
42+
TabGroupWithSpaceAbove,
4243
],
4344
});
4445

@@ -687,6 +688,45 @@ describe('MDC-based MatTabGroup', () => {
687688
}));
688689
});
689690

691+
describe('tall tabs', () => {
692+
beforeEach(() => {
693+
window.scrollTo({top: 0});
694+
});
695+
696+
it('should not scroll when changing tabs by clicking', fakeAsync(() => {
697+
const fixture = TestBed.createComponent(TabGroupWithSpaceAbove);
698+
fixture.detectChanges();
699+
tick();
700+
fixture.detectChanges();
701+
702+
window.scrollBy(0, 250);
703+
expect(window.scrollY).toBe(250);
704+
705+
// select the second tab
706+
let tabLabel = fixture.debugElement.queryAll(By.css('.mat-mdc-tab'))[1];
707+
tabLabel.nativeElement.click();
708+
checkSelectedIndex(1, fixture);
709+
710+
expect(window.scrollY).toBe(250);
711+
tick();
712+
}));
713+
714+
it('should not scroll when changing tabs programatically', fakeAsync(() => {
715+
const fixture = TestBed.createComponent(TabGroupWithSpaceAbove);
716+
fixture.detectChanges();
717+
tick();
718+
fixture.detectChanges();
719+
720+
window.scrollBy(0, 250);
721+
expect(window.scrollY).toBe(250);
722+
723+
fixture.componentInstance.tabGroup.selectedIndex = 1;
724+
fixture.detectChanges();
725+
726+
expect(window.scrollY).toBe(250);
727+
tick();
728+
}));
729+
});
690730

691731
/**
692732
* Checks that the `selectedIndex` has been updated; checks that the label and body have their
@@ -1089,3 +1129,24 @@ class TabGroupWithIndirectDescendantTabs {
10891129
class TabGroupWithInkBarFitToContent {
10901130
fitInkBarToContent = true;
10911131
}
1132+
1133+
@Component({
1134+
template: `
1135+
<div style="height: 300px; background-color: aqua">
1136+
Top Content here
1137+
</div>
1138+
<mat-tab-group>
1139+
<ng-container>
1140+
<mat-tab label="One">
1141+
<div style="height: 3000px; background-color: red"></div>
1142+
</mat-tab>
1143+
<mat-tab label="Two">
1144+
<div style="height: 3000px; background-color: green"></div>
1145+
</mat-tab>
1146+
</ng-container>
1147+
</mat-tab-group>
1148+
`,
1149+
})
1150+
class TabGroupWithSpaceAbove {
1151+
@ViewChild(MatTabGroup) tabGroup: MatTabGroup;
1152+
}

src/material/tabs/tab-group.spec.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ describe('MatTabGroup', () => {
3939
TabGroupWithIsActiveBinding,
4040
NestedTabs,
4141
TabGroupWithIndirectDescendantTabs,
42+
TabGroupWithSpaceAbove,
4243
],
4344
});
4445

@@ -686,6 +687,46 @@ describe('MatTabGroup', () => {
686687
}));
687688
});
688689

690+
describe('tall tabs', () => {
691+
beforeEach(() => {
692+
window.scrollTo({top: 0});
693+
});
694+
695+
it('should not scroll when changing tabs by clicking', fakeAsync(() => {
696+
const fixture = TestBed.createComponent(TabGroupWithSpaceAbove);
697+
fixture.detectChanges();
698+
tick();
699+
fixture.detectChanges();
700+
701+
window.scrollBy(0, 250);
702+
expect(window.scrollY).toBe(250);
703+
704+
// select the second tab
705+
let tabLabel = fixture.debugElement.queryAll(By.css('.mat-tab-label'))[1];
706+
tabLabel.nativeElement.click();
707+
checkSelectedIndex(1, fixture);
708+
709+
expect(window.scrollY).toBe(250);
710+
tick();
711+
}));
712+
713+
it('should not scroll when changing tabs programatically', fakeAsync(() => {
714+
const fixture = TestBed.createComponent(TabGroupWithSpaceAbove);
715+
fixture.detectChanges();
716+
tick();
717+
fixture.detectChanges();
718+
719+
window.scrollBy(0, 250);
720+
expect(window.scrollY).toBe(250);
721+
722+
fixture.componentInstance.tabGroup.selectedIndex = 1;
723+
fixture.detectChanges();
724+
725+
expect(window.scrollY).toBe(250);
726+
tick();
727+
}));
728+
});
729+
689730
/**
690731
* Checks that the `selectedIndex` has been updated; checks that the label and body have their
691732
* respective `active` classes
@@ -1020,3 +1061,24 @@ class TabsWithCustomAnimationDuration {}
10201061
class TabGroupWithIndirectDescendantTabs {
10211062
@ViewChild(MatTabGroup) tabGroup: MatTabGroup;
10221063
}
1064+
1065+
@Component({
1066+
template: `
1067+
<div style="height: 300px; background-color: aqua">
1068+
Top Content here
1069+
</div>
1070+
<mat-tab-group>
1071+
<ng-container>
1072+
<mat-tab label="One">
1073+
<div style="height: 3000px; background-color: red"></div>
1074+
</mat-tab>
1075+
<mat-tab label="Two">
1076+
<div style="height: 3000px; background-color: green"></div>
1077+
</mat-tab>
1078+
</ng-container>
1079+
</mat-tab-group>
1080+
`,
1081+
})
1082+
class TabGroupWithSpaceAbove {
1083+
@ViewChild(MatTabGroup) tabGroup: MatTabGroup;
1084+
}

src/material/tabs/tab-group.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,10 @@ export abstract class _MatTabGroupBase extends _MatTabGroupMixinBase implements
202202

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

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

212216
if (!isFirstRun) {
213217
this.selectedIndexChange.emit(indexToSelect);
218+
// Clear the min-height, this was needed during tab change to avoid
219+
// unnecessary scrolling.
220+
this._tabBodyWrapper.nativeElement.style.minHeight = '';
214221
}
215222
});
216223
}

0 commit comments

Comments
 (0)