Auto-Play Carousel — Free HTML CSS JS Snippet

Auto-Play Carousel · Layouts · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

CSS transform sliding track
All slides live in a single flex row. Navigation sets translateX(-n*100%) on the track — no DOM manipulation, just a single CSS property change per transition.
Animated progress bar timer
A bottom bar grows from 0% to 100% width using a linear CSS transition timed to match the 4-second interval, giving users a clear visual countdown.
Expanding pill dot indicators
The active dot expands from a 7px circle to a 22px pill — CSS width and border-radius transitions communicate slide position more clearly than a simple colour change alone.
Pause on hover
mouseenter clears the advance interval and progress animation. mouseleave restarts both from zero — the user always gets a full read time after re-entering.
Pointer Events swipe support
A single pointerdown/pointerup handler on the track captures both mouse drags and touch swipes. Deltas over 40px trigger navigation.
ARIA live region
aria-live="polite" on the container and per-slide aria-hidden updates ensure screen readers announce new content without interrupting user actions.
Smooth cubic-bezier easing
The slide transition uses cubic-bezier(0.77,0,0.18,1) — an aggressive ease-in with smooth landing that gives the slide a confident, high-quality feel.
Zero dependencies
No jQuery, no Swiper, no external carousel library. Pure HTML, CSS, and ~60 lines of vanilla JavaScript that you own and can modify freely.

About this UI Snippet

Auto-Play Carousel — CSS Transform Track, Progress Bar Timer & Pointer Swipe

Screenshot of the Auto-Play Carousel snippet rendered live

A carousel is one of the most requested UI patterns in frontend development — showcasing featured content, hero slides, testimonials, or product images in a compact rotating format. This snippet delivers a production-ready auto-playing carousel in pure HTML, CSS, and vanilla JavaScript with zero dependencies: a sliding track with smooth cubic-bezier transitions, animated dot indicators, arrow navigation, a visual progress bar, pause-on-hover, and pointer-based swipe support for touch screens.

The carousel is used across virtually every category of web project — SaaS landing pages, e-commerce hero sections, portfolio showcases, marketing sites, and dashboards. Getting the implementation right matters: jank-free transitions, accessible ARIA attributes, correct swipe detection, and pause-on-hover are all expected by users and required for production quality.

The sliding track mechanism

The core of the carousel is a display: flex track containing all slides as min-width: 100% children. Navigating to slide n sets transform: translateX(-n * 100%) on the track, which shifts the entire row by one viewport-width unit. The CSS transition: transform 0.55s cubic-bezier(0.77,0,0.18,1) applies a custom easing — fast start, smooth deceleration — that feels cinematic rather than mechanical.

The progress bar timer

Each auto-play cycle is visualised with a bottom progress bar that grows from 0% to 100% width over the same duration as the interval (4 seconds). The animation uses a width CSS transition set to linear with the exact interval duration, so the bar and the slide advance in sync. When the user navigates manually, the transition is reset to none (forcing a synchronous paint), then re-applied on the next requestAnimationFrame — this reliably restarts the animation from 0% without a flash.

Dot indicators with pill active state

Each dot starts as a 7px circle. The active dot expands to a 22px-wide pill via width and border-radius transitions — a pattern that communicates both current position and progress direction more clearly than a simple colour change. Dots are <button> elements with role="tab" for keyboard and screen reader accessibility.

Pause on hover

mouseenter clears both the slide interval and progress timers. mouseleave restarts them. This prevents the carousel from advancing while the user is reading content — a standard UX expectation that many basic carousel implementations miss.

Swipe support via Pointer Events API

Rather than separate touch and mouse event handlers, the snippet uses a single pointerdown/pointerup pair on the track. The delta (clientX end minus start) determines direction: left-swipe advances, right-swipe retreats. Any delta larger than 40px counts as an intentional swipe. The Pointer Events API handles both mouse drags and touch swipes with one code path.

Accessibility

Each slide has aria-hidden="false" (current) or aria-hidden="true" (hidden), updated on every navigation. The container has role="region" and aria-live="polite", and arrow buttons have aria-label. Dot buttons have role="tab" and individual aria-label values. Pair with an animated tabs component for tabbed content that doesn't auto-advance.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Instead of tracing every timer reset by hand, paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why the progress bar's transition is set to none and reset to 0% before being re-applied on the next requestAnimationFrame, or why goTo() guards against overlapping calls with the isAnimating flag. The same assistant can help optimize it — ask whether the single pointerdown/pointerup pair for swipe detection could misfire on a simple tap-and-hold versus an intentional drag, and how you'd distinguish them more robustly. It's also a great partner for extending the carousel: ask it to add keyboard arrow-key navigation, support variable slide durations per slide, or convert it into a multi-slide-visible layout while keeping the progress bar and dot indicators in sync. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build an auto-playing content carousel in plain HTML, CSS, and JavaScript — no library, no Swiper, no jQuery.

Requirements:
- A flex track containing full-width slides, navigated by setting a single CSS transform (translateX by negative current-index times 100 percent) on the track element, with a cubic-bezier transition for the slide motion — not by hiding/showing individual slide elements.
- An auto-advance timer plus a synchronized progress bar: the bar must animate its width from 0 to 100 percent using a linear CSS transition timed to match the exact auto-advance interval, and restarting the cycle (whether from a manual navigation or an auto-advance) must reset the transition to none, snap the width back to 0 percent, then re-apply the timed transition inside a requestAnimationFrame so the animation reliably restarts from zero without a visual flash.
- Prevent overlapping transitions: track an "is animating" flag that blocks new navigation calls until the current slide transition's transitionend event fires.
- Dot indicators where the active dot is visually distinct (not just a color change) from the inactive ones, each dot clickable to jump directly to its slide.
- Pause the auto-advance timer and progress bar entirely on mouseenter over the carousel, and resume both cleanly (restarting the progress bar from zero) on mouseleave.
- Support swipe/drag navigation using the Pointer Events API (not separate touch and mouse handlers) by capturing the horizontal delta between pointerdown and pointerup, and only triggering navigation if that delta exceeds a minimum threshold in pixels.
- Every slide must carry correct aria-hidden state reflecting whether it's the current slide, updated on every navigation.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSDrop the three blocks into your page. A full-width carousel appears with four coloured slides, arrow buttons, dot indicators, and a bottom progress bar.
  2. 2
    Watch the auto-playThe carousel advances every 4 seconds. The progress bar at the bottom fills left-to-right, giving users a visual count of when the next slide arrives.
  3. 3
    Click the arrows or dotsArrow buttons navigate prev/next. Dot buttons jump to any slide directly. Both reset the timer so the current slide gets its full 4-second display time.
  4. 4
    Swipe on touch devicesDrag the track left or right — swipes larger than 40px trigger navigation. Works with both touch and mouse pointer events.
  5. 5
    Hover to pauseMove the mouse over the carousel and it pauses. The progress bar freezes. Move away and it resumes — the full 4 seconds starts again from 0.
  6. 6
    Customise slide contentEach .slide div is independent — change the gradient background, tag text, heading, description, button label, and SVG illustration. Add or remove slides and the dot system updates automatically.

Real-world uses

Common Use Cases

Hero section feature carousels
Rotate through product features, value propositions, or customer testimonials on a SaaS landing page. The progress bar keeps the page feeling dynamic without distracting from the CTA.
E-commerce promotional banners
Showcase seasonal promotions, new collections, or featured products with distinct gradient backgrounds and direct call-to-action buttons per slide.
Onboarding and tutorial slides
Walk users through app features with a full-screen carousel during onboarding. Each slide introduces one concept with a short headline and illustration.
Portfolio project showcases
Display project screenshots, case study summaries, or client testimonials in a rotating format. Pair with an image lightbox for full-size viewing.
Blog post or article feature rotators
Highlight featured articles or categories with auto-rotating cards. Each slide links to a content category with a relevant illustration or photo.
App store screenshots
Present mobile app screenshots in a horizontal carousel format — the standard pattern for app store listing pages and product landing pages.

Got questions?

Frequently Asked Questions

Change the INTERVAL constant at the top of the JS (default 4000ms). The progress bar animation automatically adjusts to match — it reads the same constant.

Duplicate any .slide div in the HTML and update its content. The JS counts slides with track.querySelectorAll(".slide") and the dot builder loops over that count — no JS changes needed.

Remove the startProgress() call at the bottom of the JS and remove the mouseenter/mouseleave listeners. The arrows and dots will still work. You can also set INTERVAL to a very large number like 99999.

Click the "↓ React" export button above the preview. The state becomes const [current, setCurrent] = useState(0). The setInterval goes in a useEffect with a cleanup return. The progress bar animation uses a key={current} on the bar element to force remount on each slide change, which restarts the CSS animation automatically.

Yes — change each slide's min-width from 100% to 33.333% and update the translateX calculation to current * (100/3)%. You will also need to guard the advance logic against going past the last group.