AniUI Academy
medium+210 XP

Build a carousel

Build a 4-slide carousel that automatically advances every second.

Prev/Next buttons and dot indicators should navigate immediately, independent of the auto-advance timer. Hovering the carousel must pause the auto-advance; moving the mouse away resumes it.

Requirements

  • A `data-testid="carousel"` container wraps the whole thing.
  • A `data-testid="active-index"` element shows the current slide index (0-based) as plain text.
  • The active slide advances by one automatically every 1000ms, wrapping from the last slide back to the first.
  • `data-testid="prev"` / `data-testid="next"` move one slide immediately; `data-testid="dot-N"` jumps directly to slide N.
  • While the mouse is over the carousel, automatic advancing is paused; it resumes once the mouse leaves.

Your workspace

import { useEffect, useState } from "react";

const SLIDES = ["Slide A", "Slide B", "Slide C", "Slide D"];

export default function App() {
  const [index, setIndex] = useState(0);

  useEffect(() => {
    // TODO: this interval should pause while the mouse is hovering the
    // carousel (see the container below), and resume once it leaves.
    const id = setInterval(() => {
      setIndex((i) => (i + 1) % SLIDES.length);
    }, 1000);
    return () => clearInterval(id);
  }, []);

  return (
    <div
      data-testid="carousel"
      style={{ fontFamily: "sans-serif", padding: 16, maxWidth: 260 }}
    >
      <p>
        Slide: <span data-testid="active-index">{index}</span>{SLIDES[index]}
      </p>
      <div style={{ display: "flex", gap: 8 }}>
        <button data-testid="prev" onClick={() => setIndex((i) => (i - 1 + SLIDES.length) % SLIDES.length)}>
          Prev
        </button>
        <button data-testid="next" onClick={() => setIndex((i) => (i + 1) % SLIDES.length)}>
          Next
        </button>
      </div>
      <div style={{ display: "flex", gap: 6, marginTop: 8 }}>
        {SLIDES.map((_, i) => (
          <button
            key={i}
            data-testid={`dot-${i}`}
            onClick={() => setIndex(i)}
            style={{ fontWeight: i === index ? "bold" : "normal" }}
          >
            {"\u25CF"}
          </button>
        ))}
      </div>
    </div>
  );
}

Ready to check it?

5 tests run against your rendered component, right here in your browser. Sign in to claim the XP when you pass.

Stuck? The react course covers the ideas this problem is built on.