Skip to main content

Overview

The ImageCarousel component is a full-featured image slider that displays project images with:
  • Automatic slideshow with configurable interval
  • Manual navigation with previous/next buttons
  • Thumbnail strip for quick image selection (hidden on mobile)
  • Image counter badge
  • Blur backdrop effect for visual depth
  • Pause on hover functionality
  • Responsive 16:9 aspect ratio
  • Styled with School Science brand colors

Props

images
string[]
default:"[]"
Array of image URLs to display in the carousel
alt
string
default:"'Imagen del proyecto'"
Alt text for the images. The component appends the image index to this value
autoPlay
boolean
default:"true"
Enable or disable automatic slideshow playback
interval
number
default:"4000"
Time in milliseconds between automatic slide transitions (default: 4 seconds)

Usage Example

From ProyectoDetalle.jsx, showing how the carousel is used to display project images:
import ImageCarousel from "../components/ImageCarousel";
import proyectos from "../data/proyectos";
import { useParams } from "react-router-dom";

export default function DetalleProyecto() {
  const { slug } = useParams();
  const proyectoData = proyectos.find((p) => p.id === slug);

  return (
    <div>
      {proyectoData.imagenes && (
        <ImageCarousel
          images={proyectoData.imagenes}
          alt={proyectoData.titulo}
          autoPlay={true}
          interval={4000}
        />
      )}
    </div>
  );
}

Component Features

Auto-Play Mechanism

The carousel uses React’s useEffect hook to implement auto-play:
useEffect(() => {
  if (!autoPlay || isPaused || images.length <= 1) return;
  const timer = setInterval(() => {
    setCurrentIndex((prev) => (prev === images.length - 1 ? 0 : prev + 1));
  }, interval);
  return () => clearInterval(timer);
}, [autoPlay, isPaused, images.length, interval]);
Auto-play automatically pauses when the user hovers over the carousel or manually clicks navigation controls.
The carousel provides three ways to navigate:
  1. Previous/Next Buttons - Circular buttons on left/right sides
  2. Thumbnail Strip - Click any thumbnail to jump to that image (desktop only)
  3. Auto-play - Automatic progression every 4 seconds (configurable)

Responsive Behavior

The thumbnail strip is hidden on screens smaller than 1100px:
@media screen and (max-width: 1100px) {
  display: none;
}

Styling Details

Container Styles

style={{
  position: "relative",
  borderRadius: "2rem",
  overflow: "hidden",
  backgroundColor: "#0a0a0a",
  boxShadow: "0 0 30px rgba(21, 245, 186, 0.3)",
  aspectRatio: "16 / 9",
  width: "100%",
}}

Blur Backdrop Effect

The carousel creates visual depth with a blurred background layer:
<div style={{
  position: "absolute",
  inset: 0,
  backgroundImage: `url(${images[currentIndex]})`,
  backgroundSize: "cover",
  backgroundPosition: "center",
  filter: "blur(20px) brightness(0.5)",
  transform: "scale(1.1)",
  zIndex: 1,
}} />
Buttons are styled with the purple accent color:
function navButtonStyle(position) {
  return {
    position: "absolute",
    top: "50%",
    [position]: "12px",
    transform: "translateY(-50%)",
    height: 42,
    width: 42,
    borderRadius: "50%",
    border: "none",
    cursor: "pointer",
    backgroundColor: "rgba(131, 111, 255, 0.85)",
    color: "#F0F3FF",
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
  };
}

Image Counter Badge

Displays current position in top-right corner:
<div style={{
  position: "absolute",
  top: 16,
  right: 16,
  padding: "6px 12px",
  borderRadius: "999px",
  fontSize: "14px",
  fontWeight: 600,
  backgroundColor: "rgba(21, 245, 186, 0.9)",
  color: "#211951",
  zIndex: 10,
}}>
  {currentIndex + 1} / {images.length}
</div>

Thumbnail Strip

The thumbnail strip is implemented with styled-components:
import styled from "styled-components";

const MiContenedorFlotante = styled.div`
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  justify-content: center;
  gap: 8px;
  padding: 10px;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);
  z-index: 10;
  @media screen and (max-width: 1100px) {
    display: none;
  }
`;

Thumbnail Behavior

  • Active thumbnail has a 2px solid #15F5BA border
  • Inactive thumbnails have a 1px solid rgba(255,255,255,0.5) border
  • Clicking a thumbnail pauses auto-play and jumps to that image
  • Each thumbnail is 50×50px with 8px border-radius

Performance Optimization

The carousel uses lazy loading for images:
loading={currentIndex === 0 ? "eager" : "lazy"}
Only the first image loads eagerly, while others load lazily for better performance.

State Management

The component manages two pieces of state:
const [currentIndex, setCurrentIndex] = useState(0);
const [isPaused, setIsPaused] = useState(false);
  • currentIndex - Currently displayed image (0-based)
  • isPaused - Whether auto-play is paused

Icons Used

import { ChevronLeft, ChevronRight } from "lucide-react";
This component uses Lucide React icons instead of Material-UI icons for the navigation chevrons.

Customization Examples

Faster Auto-Play

<ImageCarousel
  images={projectImages}
  interval={2000} // 2 seconds instead of 4
/>

Disable Auto-Play

<ImageCarousel
  images={projectImages}
  autoPlay={false}
/>

Custom Alt Text

<ImageCarousel
  images={projectImages}
  alt="Experimento de química"
/>

Build docs developers (and LLMs) love