From 2110f2c97ec8d9b84ee4f8bcd47ca7b95d398879 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Tue, 28 May 2024 17:06:00 +0200 Subject: [PATCH] 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. (cherry picked from commit cc00a74ea50df0ea076bfa887f25a023d9bb749f) --- src/material/tabs/paginated-tab-header.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/material/tabs/paginated-tab-header.ts b/src/material/tabs/paginated-tab-header.ts index cc5363ad6c38..7c6f2264b2f6 100644 --- a/src/material/tabs/paginated-tab-header.ts +++ b/src/material/tabs/paginated-tab-header.ts @@ -550,18 +550,27 @@ export abstract class MatPaginatedTabHeader if (this.disablePagination) { this._showPaginationControls = false; } else { - const isEnabled = - this._tabListInner.nativeElement.scrollWidth > this._elementRef.nativeElement.offsetWidth; + const scrollWidth = this._tabListInner.nativeElement.scrollWidth; + const containerWidth = this._elementRef.nativeElement.offsetWidth; + + // Usually checking that the scroll width is greater than the container width should be + // enough, but on Safari at specific widths the browser ends up rounding up when there's + // no pagination and rounding down once the pagination is added. This can throw the component + // into an infinite loop where the pagination shows up and disappears constantly. We work + // around it by adding a threshold to the calculation. From manual testing the threshold + // can be lowered to 2px and still resolve the issue, but we set a higher one to be safe. + // This shouldn't cause any content to be clipped, because tabs have a 24px horizontal + // padding. See b/316395154 for more information. + const isEnabled = scrollWidth - containerWidth >= 5; if (!isEnabled) { this.scrollDistance = 0; } if (isEnabled !== this._showPaginationControls) { + this._showPaginationControls = isEnabled; this._changeDetectorRef.markForCheck(); } - - this._showPaginationControls = isEnabled; } }