Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

nscott's avatar

Carousel autoplay jumps depending on how many clicks a user does

I have a pretty basic carousel component using apline.js. It has autoloop going but it allows a user to stop this by clicking either forward or backward if they want to. Then after a given time, the autoplay starts again. However, once autoloop starts back up, the images no longer loop smoothly but instead jump in groups based on how many clicks a user made. So if I clicked twice, it would advance forward 2 images at a time. If I clicked 4 times it would advance 4 at a time etc. I have been banging my head on this one. Here is the code as is now:

<div class="carousel" x-data="carousel()" x-init="startAutoplay">
    <button class="carousel-control left" x-on:click="prev(); stopAutoplay(); startAutoplayAfterDelay(3000)">&lt;</button>
    <div x-ref="container" class="carousel-container">
        <!-- Set the order of items based on the current index -->
        <template x-for="(item, index) in items" :key="index">
            <div x-bind:class="'carousel-item order-' + ((index + current) % items.length)" x-transition:enter="transition ease-out duration-3000" 
            x-transition:enter-start="opacity-0 transform translate-x-4" x-transition:enter-end="opacity-100 transform translate-x-0" 
            x-transition:leave="transition ease-in duration-3000" x-transition:leave-start="opacity-100 transform translate-x-0" x-transition:leave-end="opacity-0 transform -translate-x-4">
               
                <img :src="item.image" alt="Carousel Item">
            </div>
        </template>
    </div>
    <button class="carousel-control right" x-on:click="next(); stopAutoplay(); startAutoplayAfterDelay(3000)">&gt;</button>
</div>

<script>
    function carousel() {
        return {
            current: 0,
            autoplayInterval: null,
            items: [
                // Add your carousel items here
              
                // ...
            ],
            startAutoplay() {
                this.autoplayTimeout = setTimeout(() => {
                    this.next();
                    this.startAutoplay(); // Start the next transition after a delay
                }, 2500); // Change the delay (in milliseconds) according to your needs
            },
            stopAutoplay() {
                clearInterval(this.autoplayInterval);
            },
            startAutoplayAfterDelay(delay) {
                this.stopAutoplay(); // Stop the current interval
                setTimeout(() => {
                    this.startAutoplay();
                }, delay);
            },
            next() {
                this.current = (this.current + 1) % this.items.length;
            },
            prev() {
                this.current = (this.current - 1 + this.items.length) % this.items.length;
            },
            getOrderClass(index) {
                // Calculate the order dynamically based on the number of items
                return 'order-' + ((index + this.current) % this.items.length + 1);
            },
        };
    }
</script>

I am currently just hardcoding images, until we pull from the DB. Any help is a appreciated.

0 likes
1 reply
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

It looks like the issue you're experiencing with the carousel advancing multiple images at a time after user interaction is due to the startAutoplay function being called multiple times without properly clearing the previous timeouts. This can cause multiple intervals to be set up, each advancing the carousel, which results in the jumping behavior you're seeing.

To fix this, you need to ensure that any existing autoplay timeout is cleared before starting a new one. In your code, you have a variable named autoplayInterval, but you're actually using setTimeout and clearInterval, which is a mismatch. You should use clearTimeout to clear a timeout set with setTimeout.

Here's the corrected code:

function carousel() {
    return {
        current: 0,
        autoplayTimeout: null, // Renamed from autoplayInterval to autoplayTimeout
        items: [
            // Add your carousel items here
            // ...
        ],
        startAutoplay() {
            this.stopAutoplay(); // Ensure any existing autoplay is stopped before starting a new one
            this.autoplayTimeout = setTimeout(() => {
                this.next();
                this.startAutoplay(); // Start the next transition after a delay
            }, 2500); // Change the delay (in milliseconds) according to your needs
        },
        stopAutoplay() {
            clearTimeout(this.autoplayTimeout); // Use clearTimeout instead of clearInterval
        },
        startAutoplayAfterDelay(delay) {
            this.stopAutoplay(); // Stop the current interval
            setTimeout(() => {
                this.startAutoplay();
            }, delay);
        },
        next() {
            this.current = (this.current + 1) % this.items.length;
        },
        prev() {
            this.current = (this.current - 1 + this.items.length) % this.items.length;
        },
        getOrderClass(index) {
            // Calculate the order dynamically based on the number of items
            return 'order-' + ((index + this.current) % this.items.length + 1);
        },
    };
}

With these changes, the startAutoplay function will clear any existing timeout before setting a new one, which should prevent the carousel from advancing multiple images at once after user interaction. Remember to also update any other references to autoplayInterval in your code to autoplayTimeout to maintain consistency.

Please or to participate in this conversation.