In BigCommerce, the code to power the carousels (slick) runs as soon as possible and blocks the main thread until it has built and started all the carousels on the page. This blocking of the main thread means the browser can’t do anything else until it has finished. Displaying of the page (rendering) can be delayed, and users can’t interact with the page while it runs.

This has a negative effect on two out of three Google Core Web Vitals. Largest Contentful Paint (LCP), which is how long it takes to display most of the visible part of the page, and First Input Delay (FID), how long it takes the page to react to a user’s interaction.

There is little value in animating a carousel if the user can’t see it yet, or interact with the page!

This article explains a way to delay the building of the carousels as well as splitting the code up so that it does not block the main thread for an extended period.

Changes to the carousel code

The core change is to add the ability to delay when a carousel is built. And in the process, we will build in the functionality to split up each carousel builder into its own quicker task.

In your theme, look for $carousel.slick. This is the function that builds a carousel. We are interested in the call used to make the general carousels, not the one to power the quick-view, as it is based on user interaction.

Then you want to change the code like this. This example is based on Cornerstone 6.30. The changes are in red:

        // Let each carousel define its own delay
        const delay = $"slickDelay") || 0;

        setTimeout(() => {
                accessibility: false,
                arrows: isMultipleSlides,
                dots: isMultipleSlides,
        }, delay);  

First, we get how long to delay the carousel. If no delay is specified, we delay for 0 milliseconds. This is a little trick to break the blocking of the main thread. The thread moves on to another task and will return to this one when it is ready—letting other activities happen in the gaps, like rendering or processing user interactions.

Please look at Optimizing Long Tasks for more details on this technique, plus some more advanced solutions.

Setting delays on each carousel

Now we have the core support for specifying delays, we can set the delay for each carousel.

You can find where carousels are by searching for data-slick. This is how the carousel code finds carousels to create.

On that element, you can now add the data-slick-delay attribute and specify how many milliseconds to delay the carouse. e.g.

<section class="heroCarousel"
        "arrows": {{arrows}},
        "mobileFirst": true,
        "slidesToShow": 1,
        "slidesToScroll": 1,
        "autoplay": true,
        "autoplaySpeed": {{carousel.swap_frequency}},
        "lazyLoad": "anticipated",
        "accessibility": false

Making sure the display is steady

Delaying the building of a carousel means there is some time when the original HTML is displayed before the carousel code changes it to be a carousel. At times this original HTML does not match up with how the final carousel looks.

Even without the delay, you should tidy things up so that the page transitions from the original HTML to the carousel with as little visual glitches as possible. It does not look nice for users and can cause Layout Shifts that contribute to Google’s Cumulative Layout Shift metric.

Check that things are stable on several devices and widths. Hopefully there is nothing to do, or just a few bits of CSS can fix it.

Largest Contentful Paint (LCP) bug

The last time I tested, there was a bug (limitation) in how Google determines the Largest Contentful Paint. It will choose the main carousel image (that is delayed) if it shows before any interaction by the user. This can mean LCP becomes the delayed time, not the time when the carousel image was visible.

This is more likely for carousels at the top of the page. If you see LCP increasing for those pages, it may be safest to specify a zero-length delay for now.