diff --git a/src/components/carousel/carousel.component.ts b/src/components/carousel/carousel.component.ts index 55cbbc1aa..98c6e93f3 100644 --- a/src/components/carousel/carousel.component.ts +++ b/src/components/carousel/carousel.component.ts @@ -506,21 +506,30 @@ export default class SlCarousel extends ShoelaceElement { } private scrollToSlide(slide: HTMLElement, behavior: ScrollBehavior = 'smooth') { - const scrollContainer = this.scrollContainer; - const scrollContainerRect = scrollContainer.getBoundingClientRect(); - const nextSlideRect = slide.getBoundingClientRect(); - - const nextLeft = nextSlideRect.left - scrollContainerRect.left; - const nextTop = nextSlideRect.top - scrollContainerRect.top; - - if (nextLeft || nextTop) { - this.pendingSlideChange = true; - scrollContainer.scrollTo({ - left: nextLeft + scrollContainer.scrollLeft, - top: nextTop + scrollContainer.scrollTop, - behavior - }); - } + // Since the geometry doesn't happen until rAF, we don't know if we'll be scrolling or not... + // It's best to assume that we will and cleanup in the else case below if we didn't need to + this.pendingSlideChange = true; + window.requestAnimationFrame(() => { + const scrollContainer = this.scrollContainer; + const scrollContainerRect = scrollContainer.getBoundingClientRect(); + const nextSlideRect = slide.getBoundingClientRect(); + + const nextLeft = nextSlideRect.left - scrollContainerRect.left; + const nextTop = nextSlideRect.top - scrollContainerRect.top; + + if (nextLeft || nextTop) { + // This is here just in case someone set it back to false + // between rAF being requested and the callback actually running + this.pendingSlideChange = true; + scrollContainer.scrollTo({ + left: nextLeft + scrollContainer.scrollLeft, + top: nextTop + scrollContainer.scrollTop, + behavior + }); + } else { + this.pendingSlideChange = false; + } + }); } render() {