20 / 22
All 22 in 22 Tailwind CSS Image Carousel
- 01Tailwind E-commerce Product Gallery Carousel with Thumbnails
- 02Tailwind Shop the Look Multi-Item Card Slider with Scroll Snap
- 03Tailwind Infinite Logo Scroller Marquee with No JavaScript
- 04Tailwind Product Colour Variant Picker Slider
- 05Tailwind Full-Screen Hero Slideshow with Auto Cross-Fade
- 06Tailwind Testimonial Card Carousel with Star Ratings
- 07Tailwind Meet the Team Profile Slider with Circular Portraits
- 08Tailwind Portfolio Gallery Slider with Hover Caption Reveal
- 09Tailwind Netflix-Style Content Row Carousel with Hover Expand
- 10Tailwind Magazine Split-Screen Article Slider
- 11Tailwind Onboarding Slider with Native CSS Scroll-Marker Dots
- 12Tailwind Vertical Image Carousel with Y-Axis Scroll Snap
- 13Tailwind 3D Coverflow Carousel with Perspective Transforms
- 14Tailwind Cross-Fade Image Slideshow with Manual Controls
- 15Tailwind Dual Opposite-Direction Marquee Slider
- 16Tailwind Dot Pagination Carousel with Target and Has Selectors
- 17Tailwind Prev / Next Arrow Carousel with Native Scroll Buttons
- 18Tailwind Before / After Image Comparison Slider
- 19Tailwind Accordion Expanding Image Panel Carousel
- 20Tailwind Autoplay Slider with Keyframe Track and Progress Bars
- 21Tailwind Zoom-on-Hover Image Gallery Slider
- 22Tailwind Parallax Text-Over-Image Story Slider
Tailwind Autoplay Slider with Keyframe Track and Progress Bars
A hands-off banner that advances itself by translating one track through each slide on a keyframe loop, with progress bars that fill in step. Two animation tokens, three arbitrary delays, and no timer to leak or desync in a background tab.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tcar-20 w-full min-h-svh grid place-items-center bg-tcar20-bg font-tcar20-sans px-5 py-10" aria-label="Auto-rotating banner" aria-roledescription="carousel">
<div class="group relative w-[min(680px,100%)] rounded-2xl overflow-hidden shadow-[0_26px_50px_-32px_oklch(0_0_0/0.9)]">
<div class="flex w-[300%] animate-tcar20-slide group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused] motion-reduce:animate-none">
<div class="w-1/3 aspect-[2/1]"><img src="https://picsum.photos/seed/auto-1/1000/500" width="1000" height="500" fetchpriority="high" decoding="async" alt="Summer sale banner" class="size-full object-cover block"></div>
<div class="w-1/3 aspect-[2/1]"><img src="https://picsum.photos/seed/auto-2/1000/500" width="1000" height="500" loading="lazy" decoding="async" alt="New arrivals banner" class="size-full object-cover block"></div>
<div class="w-1/3 aspect-[2/1]"><img src="https://picsum.photos/seed/auto-3/1000/500" width="1000" height="500" loading="lazy" decoding="async" alt="Free shipping banner" class="size-full object-cover block"></div>
</div>
<div aria-hidden="true" class="absolute inset-x-3.5 bottom-3.5 flex gap-2 motion-reduce:hidden">
<span class="relative flex-1 h-1 rounded-full bg-tcar20-track shadow-[0_0_0_1px_oklch(0_0_0/0.28)] overflow-hidden"><span class="absolute inset-0 bg-tcar20-acc origin-left scale-x-0 animate-tcar20-bar group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused]"></span></span>
<span class="relative flex-1 h-1 rounded-full bg-tcar20-track shadow-[0_0_0_1px_oklch(0_0_0/0.28)] overflow-hidden"><span class="absolute inset-0 bg-tcar20-acc origin-left scale-x-0 animate-tcar20-bar [animation-delay:-10s] group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused]"></span></span>
<span class="relative flex-1 h-1 rounded-full bg-tcar20-track shadow-[0_0_0_1px_oklch(0_0_0/0.28)] overflow-hidden"><span class="absolute inset-0 bg-tcar20-acc origin-left scale-x-0 animate-tcar20-bar [animation-delay:-5s] group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused]"></span></span>
</div>
</div>
</section><section class="tcar-20 w-full min-h-svh grid place-items-center bg-tcar20-bg font-tcar20-sans px-5 py-10" aria-label="Auto-rotating banner" aria-roledescription="carousel">
<div class="group relative w-[min(680px,100%)] rounded-2xl overflow-hidden shadow-[0_26px_50px_-32px_oklch(0_0_0/0.9)]">
<div class="flex w-[300%] animate-tcar20-slide group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused] motion-reduce:animate-none">
<div class="w-1/3 aspect-[2/1]"><img src="https://picsum.photos/seed/auto-1/1000/500" width="1000" height="500" fetchpriority="high" decoding="async" alt="Summer sale banner" class="size-full object-cover block"></div>
<div class="w-1/3 aspect-[2/1]"><img src="https://picsum.photos/seed/auto-2/1000/500" width="1000" height="500" loading="lazy" decoding="async" alt="New arrivals banner" class="size-full object-cover block"></div>
<div class="w-1/3 aspect-[2/1]"><img src="https://picsum.photos/seed/auto-3/1000/500" width="1000" height="500" loading="lazy" decoding="async" alt="Free shipping banner" class="size-full object-cover block"></div>
</div>
<div aria-hidden="true" class="absolute inset-x-3.5 bottom-3.5 flex gap-2 motion-reduce:hidden">
<span class="relative flex-1 h-1 rounded-full bg-tcar20-track shadow-[0_0_0_1px_oklch(0_0_0/0.28)] overflow-hidden"><span class="absolute inset-0 bg-tcar20-acc origin-left scale-x-0 animate-tcar20-bar group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused]"></span></span>
<span class="relative flex-1 h-1 rounded-full bg-tcar20-track shadow-[0_0_0_1px_oklch(0_0_0/0.28)] overflow-hidden"><span class="absolute inset-0 bg-tcar20-acc origin-left scale-x-0 animate-tcar20-bar [animation-delay:-10s] group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused]"></span></span>
<span class="relative flex-1 h-1 rounded-full bg-tcar20-track shadow-[0_0_0_1px_oklch(0_0_0/0.28)] overflow-hidden"><span class="absolute inset-0 bg-tcar20-acc origin-left scale-x-0 animate-tcar20-bar [animation-delay:-5s] group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused]"></span></span>
</div>
</div>
</section>@import "tailwindcss";
@theme {
--color-tcar20-bg: #1a0f18;
--color-tcar20-bg: oklch(0.21 0.035 340);
--color-tcar20-track: #ffffff;
--color-tcar20-track: oklch(1 0 0 / 0.4);
--color-tcar20-acc: #ea4c95;
--color-tcar20-acc: oklch(0.68 0.2 350);
--font-tcar20-sans: 'Archivo', system-ui, sans-serif;
--animate-tcar20-slide: tcar20-slide 15s infinite;
--animate-tcar20-bar: tcar20-bar 15s infinite;
}
@keyframes tcar20-slide {
0%,
28% {
transform: translateX(0);
}
33%,
61% {
transform: translateX(-33.3333%);
}
66%,
94% {
transform: translateX(-66.6666%);
}
100% {
transform: translateX(0);
}
}
@keyframes tcar20-bar {
0% {
transform: scaleX(0);
}
28% {
transform: scaleX(1);
}
33%,
100% {
transform: scaleX(0);
}
}
.tcar-20 {
width: 100%;
min-height: 100svh;
}
.tcar-20 ::selection {
background: var(--color-tcar20-acc);
color: #fff;
}@import "tailwindcss";
@theme {
--color-tcar20-bg: #1a0f18;
--color-tcar20-bg: oklch(0.21 0.035 340);
--color-tcar20-track: #ffffff;
--color-tcar20-track: oklch(1 0 0 / 0.4);
--color-tcar20-acc: #ea4c95;
--color-tcar20-acc: oklch(0.68 0.2 350);
--font-tcar20-sans: 'Archivo', system-ui, sans-serif;
--animate-tcar20-slide: tcar20-slide 15s infinite;
--animate-tcar20-bar: tcar20-bar 15s infinite;
}
@keyframes tcar20-slide {
0%,
28% {
transform: translateX(0);
}
33%,
61% {
transform: translateX(-33.3333%);
}
66%,
94% {
transform: translateX(-66.6666%);
}
100% {
transform: translateX(0);
}
}
@keyframes tcar20-bar {
0% {
transform: scaleX(0);
}
28% {
transform: scaleX(1);
}
33%,
100% {
transform: scaleX(0);
}
}
.tcar-20 {
width: 100%;
min-height: 100svh;
}
.tcar-20 ::selection {
background: var(--color-tcar20-acc);
color: #fff;
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme {
--color-tcar20-bg: #1a0f18;
--color-tcar20-bg: oklch(0.21 0.035 340);
--color-tcar20-track: #ffffff;
--color-tcar20-track: oklch(1 0 0 / 0.4);
--color-tcar20-acc: #ea4c95;
--color-tcar20-acc: oklch(0.68 0.2 350);
--font-tcar20-sans: 'Archivo', system-ui, sans-serif;
--animate-tcar20-slide: tcar20-slide 15s infinite;
--animate-tcar20-bar: tcar20-bar 15s infinite;
}
@keyframes tcar20-slide {
0%,
28% {
transform: translateX(0);
}
33%,
61% {
transform: translateX(-33.3333%);
}
66%,
94% {
transform: translateX(-66.6666%);
}
100% {
transform: translateX(0);
}
}
@keyframes tcar20-bar {
0% {
transform: scaleX(0);
}
28% {
transform: scaleX(1);
}
33%,
100% {
transform: scaleX(0);
}
}
.tcar-20 {
width: 100%;
min-height: 100svh;
}
.tcar-20 ::selection {
background: var(--color-tcar20-acc);
color: #fff;
}@import "tailwindcss";
@theme {
--color-tcar20-bg: #1a0f18;
--color-tcar20-bg: oklch(0.21 0.035 340);
--color-tcar20-track: #ffffff;
--color-tcar20-track: oklch(1 0 0 / 0.4);
--color-tcar20-acc: #ea4c95;
--color-tcar20-acc: oklch(0.68 0.2 350);
--font-tcar20-sans: 'Archivo', system-ui, sans-serif;
--animate-tcar20-slide: tcar20-slide 15s infinite;
--animate-tcar20-bar: tcar20-bar 15s infinite;
}
@keyframes tcar20-slide {
0%,
28% {
transform: translateX(0);
}
33%,
61% {
transform: translateX(-33.3333%);
}
66%,
94% {
transform: translateX(-66.6666%);
}
100% {
transform: translateX(0);
}
}
@keyframes tcar20-bar {
0% {
transform: scaleX(0);
}
28% {
transform: scaleX(1);
}
33%,
100% {
transform: scaleX(0);
}
}
.tcar-20 {
width: 100%;
min-height: 100svh;
}
.tcar-20 ::selection {
background: var(--color-tcar20-acc);
color: #fff;
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Archivo:wght@400;600;700;800&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Archivo:wght@400;600;700;800&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- Two
@themeanimation tokens sharing one duration is what keeps the track and the bars honest. Change15sin one and the component desyncs immediately — which is an argument for a shared--durationvalue the moment a third animation joins. - The bar fill animates
transform: scaleX()from aorigin-leftelement, neverwidth. Three width animations running continuously behind a banner would be a measurable INP cost. - UI change from the CSS original: the bars are
motion-reduce:hiddenrather thandisplay:noneinside a media query, and the accent lifted from#db2777tooklch(0.68 0.2 350)so the 4px fill is visible against the translucent white track on bright banner artwork.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Autoplay Slider with Keyframe Track and Progress Bars
Source: https://codefronts.com/snippets/tailwind-css-image-carousel/tailwind-autoplay-slider-keyframe-track/
A hands-off banner that advances itself by translating one track through each slide on a keyframe loop, with progress bars that fill in step. Two animation tokens, three arbitrary delays, and no timer to leak or desync in a background tab.
## HTML
```html
<section class="tcar-20 w-full min-h-svh grid place-items-center bg-tcar20-bg font-tcar20-sans px-5 py-10" aria-label="Auto-rotating banner" aria-roledescription="carousel">
<div class="group relative w-[min(680px,100%)] rounded-2xl overflow-hidden shadow-[0_26px_50px_-32px_oklch(0_0_0/0.9)]">
<div class="flex w-[300%] animate-tcar20-slide group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused] motion-reduce:animate-none">
<div class="w-1/3 aspect-[2/1]"><img src="https://picsum.photos/seed/auto-1/1000/500" width="1000" height="500" fetchpriority="high" decoding="async" alt="Summer sale banner" class="size-full object-cover block"></div>
<div class="w-1/3 aspect-[2/1]"><img src="https://picsum.photos/seed/auto-2/1000/500" width="1000" height="500" loading="lazy" decoding="async" alt="New arrivals banner" class="size-full object-cover block"></div>
<div class="w-1/3 aspect-[2/1]"><img src="https://picsum.photos/seed/auto-3/1000/500" width="1000" height="500" loading="lazy" decoding="async" alt="Free shipping banner" class="size-full object-cover block"></div>
</div>
<div aria-hidden="true" class="absolute inset-x-3.5 bottom-3.5 flex gap-2 motion-reduce:hidden">
<span class="relative flex-1 h-1 rounded-full bg-tcar20-track shadow-[0_0_0_1px_oklch(0_0_0/0.28)] overflow-hidden"><span class="absolute inset-0 bg-tcar20-acc origin-left scale-x-0 animate-tcar20-bar group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused]"></span></span>
<span class="relative flex-1 h-1 rounded-full bg-tcar20-track shadow-[0_0_0_1px_oklch(0_0_0/0.28)] overflow-hidden"><span class="absolute inset-0 bg-tcar20-acc origin-left scale-x-0 animate-tcar20-bar [animation-delay:-10s] group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused]"></span></span>
<span class="relative flex-1 h-1 rounded-full bg-tcar20-track shadow-[0_0_0_1px_oklch(0_0_0/0.28)] overflow-hidden"><span class="absolute inset-0 bg-tcar20-acc origin-left scale-x-0 animate-tcar20-bar [animation-delay:-5s] group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused]"></span></span>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tcar20-bg: #1a0f18;
--color-tcar20-bg: oklch(0.21 0.035 340);
--color-tcar20-track: #ffffff;
--color-tcar20-track: oklch(1 0 0 / 0.4);
--color-tcar20-acc: #ea4c95;
--color-tcar20-acc: oklch(0.68 0.2 350);
--font-tcar20-sans: 'Archivo', system-ui, sans-serif;
--animate-tcar20-slide: tcar20-slide 15s infinite;
--animate-tcar20-bar: tcar20-bar 15s infinite;
}
@keyframes tcar20-slide {
0%,
28% {
transform: translateX(0);
}
33%,
61% {
transform: translateX(-33.3333%);
}
66%,
94% {
transform: translateX(-66.6666%);
}
100% {
transform: translateX(0);
}
}
@keyframes tcar20-bar {
0% {
transform: scaleX(0);
}
28% {
transform: scaleX(1);
}
33%,
100% {
transform: scaleX(0);
}
}
.tcar-20 {
width: 100%;
min-height: 100svh;
}
.tcar-20 ::selection {
background: var(--color-tcar20-acc);
color: #fff;
}
```Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Autoplay Slider with Keyframe Track and Progress Bars
Source: https://codefronts.com/snippets/tailwind-css-image-carousel/tailwind-autoplay-slider-keyframe-track/
A hands-off banner that advances itself by translating one track through each slide on a keyframe loop, with progress bars that fill in step. Two animation tokens, three arbitrary delays, and no timer to leak or desync in a background tab.
## HTML
```html
<section class="tcar-20 w-full min-h-svh grid place-items-center bg-tcar20-bg font-tcar20-sans px-5 py-10" aria-label="Auto-rotating banner" aria-roledescription="carousel">
<div class="group relative w-[min(680px,100%)] rounded-2xl overflow-hidden shadow-[0_26px_50px_-32px_oklch(0_0_0/0.9)]">
<div class="flex w-[300%] animate-tcar20-slide group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused] motion-reduce:animate-none">
<div class="w-1/3 aspect-[2/1]"><img src="https://picsum.photos/seed/auto-1/1000/500" width="1000" height="500" fetchpriority="high" decoding="async" alt="Summer sale banner" class="size-full object-cover block"></div>
<div class="w-1/3 aspect-[2/1]"><img src="https://picsum.photos/seed/auto-2/1000/500" width="1000" height="500" loading="lazy" decoding="async" alt="New arrivals banner" class="size-full object-cover block"></div>
<div class="w-1/3 aspect-[2/1]"><img src="https://picsum.photos/seed/auto-3/1000/500" width="1000" height="500" loading="lazy" decoding="async" alt="Free shipping banner" class="size-full object-cover block"></div>
</div>
<div aria-hidden="true" class="absolute inset-x-3.5 bottom-3.5 flex gap-2 motion-reduce:hidden">
<span class="relative flex-1 h-1 rounded-full bg-tcar20-track shadow-[0_0_0_1px_oklch(0_0_0/0.28)] overflow-hidden"><span class="absolute inset-0 bg-tcar20-acc origin-left scale-x-0 animate-tcar20-bar group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused]"></span></span>
<span class="relative flex-1 h-1 rounded-full bg-tcar20-track shadow-[0_0_0_1px_oklch(0_0_0/0.28)] overflow-hidden"><span class="absolute inset-0 bg-tcar20-acc origin-left scale-x-0 animate-tcar20-bar [animation-delay:-10s] group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused]"></span></span>
<span class="relative flex-1 h-1 rounded-full bg-tcar20-track shadow-[0_0_0_1px_oklch(0_0_0/0.28)] overflow-hidden"><span class="absolute inset-0 bg-tcar20-acc origin-left scale-x-0 animate-tcar20-bar [animation-delay:-5s] group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused]"></span></span>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tcar20-bg: #1a0f18;
--color-tcar20-bg: oklch(0.21 0.035 340);
--color-tcar20-track: #ffffff;
--color-tcar20-track: oklch(1 0 0 / 0.4);
--color-tcar20-acc: #ea4c95;
--color-tcar20-acc: oklch(0.68 0.2 350);
--font-tcar20-sans: 'Archivo', system-ui, sans-serif;
--animate-tcar20-slide: tcar20-slide 15s infinite;
--animate-tcar20-bar: tcar20-bar 15s infinite;
}
@keyframes tcar20-slide {
0%,
28% {
transform: translateX(0);
}
33%,
61% {
transform: translateX(-33.3333%);
}
66%,
94% {
transform: translateX(-66.6666%);
}
100% {
transform: translateX(0);
}
}
@keyframes tcar20-bar {
0% {
transform: scaleX(0);
}
28% {
transform: scaleX(1);
}
33%,
100% {
transform: scaleX(0);
}
}
.tcar-20 {
width: 100%;
min-height: 100svh;
}
.tcar-20 ::selection {
background: var(--color-tcar20-acc);
color: #fff;
}
```How this works
The animation is the scheduler. One keyframe holds each slide then steps the track, looping forever. There is no setInterval, which means nothing to clear, nothing to desync after a tab sleeps, and no work at all when the section is off-screen.
The bars are the same trick, offset. Each bar's fill runs the same 15s keyframe started at a different negative delay, so it completes exactly while its slide is showing. Keeping duration and delays in one arithmetic family is what holds them in sync.
Pausing must cover both. If the track pauses and the bars keep filling, the component immediately looks broken — so the same variant is on both.
Make it yours
- Dwell and cycle:
15sin both tokens, kept in step with the keyframe stops. - Add a slide: widen the track to
w-[400%], add a keyframe stop, add a bar with its delay. - Continuous drift: ease the keyframe instead of holding.
- Restyle or remove the bars — they are independent of the track.
Gotchas — read before shipping
- Track width must be an exact multiple of 100%, and the keyframe percentages must divide evenly by the slide count, or the timing drifts a little further every loop.
- Always pause on hover and focus. An unstoppable auto-rotating banner is an accessibility failure and an INP liability.
- Under reduced motion, hide the bars rather than freezing them — a progress bar stuck at 40% is worse than no progress bar.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Keyframe translation needs nothing modern; the floor quoted is Tailwind v4's generated sheet.