webdevpuneet.com

Hero with Auto-Rotating Background Carousel — Free HTML CSS JS Snippet

Hero with Auto-Rotating Background Carousel · Heroes · Plain HTML, CSS & JS · Live preview

CategoryHeroes

Copy & paste

Source Code

<section class="rbg-hero" id="rbgHero">
  <div class="rbg-layer rbg-layer-active" data-bg="1"></div>
  <div class="rbg-layer" data-bg="2"></div>
  <div class="rbg-layer" data-bg="3"></div>
  <div class="rbg-layer" data-bg="4"></div>
  <div class="rbg-scrim"></div>

  <div class="rbg-content">
    <span class="rbg-eyebrow">Destinations, reimagined</span>
    <h1 class="rbg-h1">Wherever you're<br>going, go further</h1>
    <p class="rbg-sub">Curated stays across four continents. Every place, one booking flow.</p>
    <a href="#" class="rbg-cta">Explore destinations</a>
  </div>

  <div class="rbg-dots" id="rbgDots">
    <button class="rbg-dot rbg-dot-active" data-index="0" aria-label="Show slide 1"></button>
    <button class="rbg-dot" data-index="1" aria-label="Show slide 2"></button>
    <button class="rbg-dot" data-index="2" aria-label="Show slide 3"></button>
    <button class="rbg-dot" data-index="3" aria-label="Show slide 4"></button>
  </div>
</section>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Real timer-driven state
activeIndex advances via setInterval, not a CSS loop.
Stacked opacity cross-fade
Layers sit on top of each other; only opacity toggles.
Clickable dots
Real controls, not passive indicators.
Timer restarts on manual click
Manual selection never gets silently overridden.
Modulo-wrapped cycling
Loops seamlessly from the last slide to the first.
Visibility-aware pausing
IntersectionObserver stops the timer when off-screen.
Fixed content layer
Headline and CTA never move or fade with the background.
Consistent-contrast scrim
Text stays legible regardless of active background.

About this UI Snippet

Hero with Auto-Rotating Background Carousel — Timed Cross-Fade with Clickable Dots

Screenshot of the Hero with Auto-Rotating Background Carousel snippet rendered live

Travel, hospitality, and real-estate hero sections often need to show range — multiple destinations or properties — without a full image slider UI competing with the headline. This snippet keeps the headline and CTA fixed in place while four full-bleed background layers cross-fade on a real timer beneath them, with indicator dots that both reflect and control the current slide.

Stacked layers, not a sliding track

All four .rbg-layer elements are absolutely positioned and stacked directly on top of each other (position: absolute; inset: 0) rather than laid out side-by-side in a scrolling track. Only the active layer has opacity: 1; every other layer sits at opacity: 0 beneath it. Switching slides means toggling one class on the outgoing layer and one on the incoming layer — the CSS transition: opacity 1.4s handles the actual cross-fade, so the "animation" is really just two class toggles plus a CSS transition, kept simple and GPU-cheap.

A real timer driving real state

activeIndex is a genuine piece of JavaScript state, advanced by setInterval(next, 4200). goTo(index) removes the active classes from the current layer and dot, computes the next index with a modulo wrap (so it cycles 0→1→2→3→0 forever), and adds the active classes to the new layer and dot — headline and CTA in .rbg-content are never touched, since they sit in a separate z-index: 2 layer above the scrim.

Dots that are real controls, not just indicators

Each dot is a <button> with a data-index; clicking one calls goTo() directly with that index — so a visitor can jump straight to slide 3 rather than waiting for the auto-rotation to arrive there. Critically, the click handler also calls startTimer() again, which clears and re-creates the interval — without this, a manual click would still get silently overridden by an in-flight timer a moment later, which is the classic bug in hand-rolled carousels.

Pausing when off-screen

An IntersectionObserver on the hero section starts the interval when the hero is visible and clears it when it scrolls out of view — so the carousel isn't burning timer cycles (and the associated reflows/repaints) on a hero the visitor has already scrolled past.

A scrim for guaranteed text contrast

A fixed .rbg-scrim gradient sits above all four background layers but below the content, so headline legibility never depends on which background happens to be active — it's darkened consistently regardless of the underlying gradient's brightness.

Customizing it

Swap the CSS gradients for real background-image photos, adjust INTERVAL_MS, or add/remove layers and dots in matching pairs (the JS reads both lists by index, so counts must stay equal). Pair it with video bg hero for a single moving background instead, or portfolio hero for a static alternative.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSThe first background is active; rotation starts automatically.
  2. 2
    Watch it cross-fadeEvery 4.2s the active layer and dot advance, wrapping after the last slide.
  3. 3
    Click a dot directlyJumps to that slide immediately and restarts the auto-rotation timer.
  4. 4
    Scroll the hero out of viewThe IntersectionObserver pauses the interval until it's visible again.
  5. 5
    Swap gradients for real photosReplace each .rbg-layer's background with background-image + cover.
  6. 6
    Add a fifth slideAdd matching .rbg-layer and .rbg-dot elements — indices must line up.

Real-world uses

Common Use Cases

Travel destination heroes
Show range across destinations while the headline and call to action stay fixed, cross-fading four backgrounds on a real setInterval timer.
Real estate featured properties
Rotate through featured listings behind one search prompt, with layers stacked and only their opacity toggling.
Event and venue pages
Cycle through photos from past events, with clickable indicator dots and a timer that restarts when someone picks a slide manually.
Restaurant and hotel sites
Compare with a video background hero when moving footage is available and a lighter image rotation when it is not.
Fashion and conference campaigns
Rotate seasonal campaign images for a brand, or show multiple venues and speakers for a summit without a full slider interface.
Related: Developer Hero with Typing Code Window
See the Developer Hero with Typing Code Window for a related heroes pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

A cross-fade. All background layers are stacked directly on top of each other with position: absolute; inset: 0, and only the active one has opacity: 1. Switching slides toggles the active class on the outgoing and incoming layers, and the CSS opacity transition handles the visual fade — nothing physically slides or translates.

goTo() jumps immediately to the clicked slide's index, and the click handler also calls startTimer() again, which clears the existing interval and creates a fresh one. This matters because without restarting the timer, the in-flight interval from before the click would still fire on its old schedule and could immediately override the slide you just manually selected.

No — an IntersectionObserver watches the hero section and calls clearInterval() when it's no longer intersecting the viewport, then calls startTimer() again once it re-enters view. This avoids burning timer cycles and layout work on a background rotation the visitor isn't currently looking at.

Replace each .rbg-layer[data-bg="N"] rule's background value with background-image: url(...); background-size: cover; background-position: center — the opacity-based cross-fade logic in the JavaScript is completely independent of what's rendered inside each layer, so no JS changes are needed.

Add a fifth .rbg-layer div with a matching data-bg value and CSS background rule, and a fifth .rbg-dot button with data-index="4" and an aria-label. Since the JavaScript reads both the .rbg-layer and .rbg-dot node lists by array index and computes wraparound with layers.length, both counts must stay equal but no other logic changes are required.