Auto-play Slider
A slideshow that advances by itself: a bar fills up, the next slide glides in, and everything stops as soon as the mouse or the keyboard lands on it.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Gallery has 44 effects, including 6 free. Explore the category →
3 usage examples



How it works
The .fx-0163-root root holds an .apl-carousel (a named region), an .apl-viewport window and an .apl-track in display:flex: each .apl-slide takes 100% of the width and the track moves by translateX(-100%) per slide in 0.5 s. An <img> placed in a slide covers it entirely (object-fit: cover); without one, the five indigo → amber demo gradients apply.
The script finds every .fx-0163-root on the page and gives each one its own timer, so two carousels on one page run independently. A requestAnimationFrame loop fills the .apl-progress bar from the time actually elapsed (steps of at most 50 ms per frame, so no jump when a hidden tab comes back); at 100% the next slide arrives and the bar starts over. Duration: data-apl-interval, 3000 ms by default, 1000 ms minimum.
Playback stops while the mouse is over the carousel, while keyboard focus is inside it, and when the carousel leaves the screen (the loop is actually stopped, not just hidden). The round button at the top right pauses or resumes; asking for playback with it overrides the hover pause. The ‹ › arrows and a horizontal drag of more than 50 px (finger or mouse) change slide and reset the bar.
Accessibility
- Carousel roles:
role="region"+aria-roledescription="carousel"and a name on the container; each slide is arole="group"announced as "slide, 2 of 5". These texts live in the HTML: translate them and update "X of N" if you change the number of slides. - Pause: a button named "Pause automatic playback" / "Resume automatic playback" depending on its state, plus a stop on hover, on keyboard focus and off screen. Hidden slides are
inert: a link inside them cannot take focus. - Announcements: the track is
aria-live="off"while playing (nothing is read every 3 s) and switches topoliteonce paused, so the slide chosen with the arrows is announced. - Reduced motion: under
prefers-reduced-motion: reducethe carousel starts paused and slides change without gliding; arrows, swipe and the play button keep working. - Touch: Pointer Events with
touch-action: pan-yon the window: a horizontal gesture changes slide, a vertical one scrolls the page as usual.
Browser compatibility
Dependency-free JavaScript (requestAnimationFrame, Pointer Events, IntersectionObserver) and the inert attribute (Chrome 102, Firefox 112, Safari 15.5 according to MDN). Measured in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): two copies with only the second one driven, playback that advances without hover and stops on hover, reduced motion, 390 px without horizontal scrolling, finger swipe (Chromium) without blocking vertical scrolling, 0 errors.
Without JavaScript the first slide stays visible and the buttons do nothing. Before Safari 15.5 / Firefox 112, inert is ignored: everything works, but a link in a hidden slide can receive focus.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0163-root" data-apl-interval="3000">
<div class="apl-carousel" role="region" aria-roledescription="carousel" aria-label="…">
<div class="apl-viewport">
<div class="apl-track" aria-live="off">
<div class="apl-slide" role="group" aria-roledescription="slide" aria-label="1 of 5"><img src="…" alt="…"></div>
…
</div>
</div>
<div class="apl-progress" aria-hidden="true"></div>
<button class="apl-toggle" type="button" aria-label="…" data-apl-label-pause="…" data-apl-label-play="…"><svg class="apl-icon-pause">…</svg><svg class="apl-icon-play">…</svg></button>
<button class="apl-arrow apl-prev" type="button" aria-label="…">…</button>
<button class="apl-arrow apl-next" type="button" aria-label="…">…</button>
</div>
</div>
One-time payment, no subscription — the code is yours forever
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Slide duration (HTML — data-apl-interval on .fx-0163-root) |
3000 (ms) | Time the bar takes to fill before the next slide. Minimum 1000 ms. For text people must read, aim for 5000 ms or more. |
Maximum width (CSS — --apl-max-width) |
640px | The carousel takes its container's width up to this limit. none to fill the whole width. |
Proportions (CSS — --apl-ratio) |
16 / 10 | Width/height ratio. auto if you set a height on the carousel yourself. |
Slide content (HTML — .apl-slide) |
5 gradients "Slide 1" to "Slide 5" | Put an <img> in it (it covers the whole slide) and/or text. Add or remove slides freely, updating their "X of N" aria-label. |
Pause button labels (HTML — data-apl-label-pause / data-apl-label-play) |
"Pause automatic playback" / "Resume automatic playback" | Name read by screen readers depending on the state; translate it with the other labels. |
Glide speed (CSS — .apl-track) |
transform .5s cubic-bezier(.25,.46,.45,.94) | Duration and curve of the transition between two slides. |
Bar colour (CSS — .apl-progress) |
gradient #6366f1 → #d946ef, 4 px | Background and height of the progress bar at the bottom of the carousel. |
FAQ
inert. When a visitor tabs to the link, playback pauses so they have time to activate it.apl-paused class on .apl-carousel): otherwise that click would start playback for people using reduced motion. For example var r = document.querySelector('.fx-0163-root'); if (!r.querySelector('.apl-paused')) r.querySelector('.apl-toggle').click();. Arrows and swipe keep working.