Skip to content

Commit cc00a74

Browse files
authored
fix(material/tabs): avoid pagination infinite loop in safari (#29121)
Fixes a bug reported internally where the tabs pagination was going into an infinite loop at some widths. The root cause is a bit unclear, but it looks like in some cases Safari rounds up the `scrollWidth` and in some it doesn't which we end up hitting when adding/removing the pagination. These changes work around it by adding a 5px threshold that needs to be crossed before we start showing the pagination. The threshold shouldn't be noticable for users since the tabs have a 24px padding on each side.
1 parent 233c8a3 commit cc00a74

File tree

1 file changed

+13
-4
lines changed

1 file changed

+13
-4
lines changed

src/material/tabs/paginated-tab-header.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -550,18 +550,27 @@ export abstract class MatPaginatedTabHeader
550550
if (this.disablePagination) {
551551
this._showPaginationControls = false;
552552
} else {
553-
const isEnabled =
554-
this._tabListInner.nativeElement.scrollWidth > this._elementRef.nativeElement.offsetWidth;
553+
const scrollWidth = this._tabListInner.nativeElement.scrollWidth;
554+
const containerWidth = this._elementRef.nativeElement.offsetWidth;
555+
556+
// Usually checking that the scroll width is greater than the container width should be
557+
// enough, but on Safari at specific widths the browser ends up rounding up when there's
558+
// no pagination and rounding down once the pagination is added. This can throw the component
559+
// into an infinite loop where the pagination shows up and disappears constantly. We work
560+
// around it by adding a threshold to the calculation. From manual testing the threshold
561+
// can be lowered to 2px and still resolve the issue, but we set a higher one to be safe.
562+
// This shouldn't cause any content to be clipped, because tabs have a 24px horizontal
563+
// padding. See b/316395154 for more information.
564+
const isEnabled = scrollWidth - containerWidth >= 5;
555565

556566
if (!isEnabled) {
557567
this.scrollDistance = 0;
558568
}
559569

560570
if (isEnabled !== this._showPaginationControls) {
571+
this._showPaginationControls = isEnabled;
561572
this._changeDetectorRef.markForCheck();
562573
}
563-
564-
this._showPaginationControls = isEnabled;
565574
}
566575
}
567576

0 commit comments

Comments
 (0)