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
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
Enable or disable automatic slideshow playback
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.
Navigation Controls
The carousel provides three ways to navigate:
- Previous/Next Buttons - Circular buttons on left/right sides
- Thumbnail Strip - Click any thumbnail to jump to that image (desktop only)
- 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
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"
/>