Over the years, I have seen many developers struggle with building a simple image slider. It often feels like you have to choose between a heavy library or a buggy custom script.
I have spent more than 8 years building React applications for various US-based clients. In my experience, the “perfect” slider depends entirely on your project’s specific requirements.
Whether you are building a real estate portal for New York listings or a national park gallery, a slider is a must. In this guide, I will show you how to build a React image slider using three different approaches.
Method 1: Build a Custom Slider from Scratch
I always recommend starting from scratch if you need a lightweight and highly specific solution.
When I built a hero section for a California-based travel agency, I went the custom route to keep the bundle size small.
This method uses the useState hook to track the current index and simple CSS transitions.
import React, { useState } from 'react';
const CustomSlider = () => {
// Example images: Beautiful US National Parks
const slides = [
{
url: 'https://images.unsplash.com/photo-1502134249126-9f3755a50d78?q=80&w=1000',
title: 'Grand Canyon, Arizona',
},
{
url: 'https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?q=80&w=1000',
title: 'Yosemite National Park, California',
},
{
url: 'https://images.unsplash.com/photo-1469474968028-56623f02e42e?q=80&w=1000',
title: 'Zion National Park, Utah',
},
];
const [currentIndex, setCurrentIndex] = useState(0);
const prevSlide = () => {
const isFirstSlide = currentIndex === 0;
const newIndex = isFirstSlide ? slides.length - 1 : currentIndex - 1;
setCurrentIndex(newIndex);
};
const nextSlide = () => {
const isLastSlide = currentIndex === slides.length - 1;
const newIndex = isLastSlide ? 0 : currentIndex + 1;
setCurrentIndex(newIndex);
};
const sliderStyles = {
height: '500px',
position: 'relative',
width: '100%',
maxWidth: '800px',
margin: '0 auto',
};
const slideStyles = {
width: '100%',
height: '100%',
borderRadius: '10px',
backgroundPosition: 'center',
backgroundSize: 'cover',
backgroundImage: `url(${slides[currentIndex].url})`,
transition: 'background-image 0.5s ease-in-out',
};
const arrowStyles = {
position: 'absolute',
top: '50%',
transform: 'translate(0, -50%)',
fontSize: '45px',
color: '#fff',
zIndex: 1,
cursor: 'pointer',
backgroundColor: 'rgba(0,0,0,0.3)',
borderRadius: '50%',
padding: '10px',
};
return (
<div style={sliderStyles}>
<div style={{ ...arrowStyles, left: '32px' }} onClick={prevSlide}>
❰
</div>
<div style={{ ...arrowStyles, right: '32px' }} onClick={nextSlide}>
❱
</div>
<div style={slideStyles}></div>
<div style={{ textAlign: 'center', marginTop: '10px' }}>
<h3>{slides[currentIndex].title}</h3>
</div>
</div>
);
};
export default CustomSlider;I executed the above example code and added the screenshot below.

I find this approach best when you don’t want to deal with the overhead of external dependencies. It gives you full control over the styling and the transition logic.
Method 2: Use the Swiper Library for Mobile-First Apps
If you are building an app where touch gestures are a priority, I usually reach for Swiper.
It is incredibly powerful and handles swipes on mobile devices much better than a custom solution. I recently used this for a luxury car rental site in Miami to showcase their fleet.
First, install the library: npm install swiper
import React from 'react';
import { Swiper, SwiperSlide } from 'swiper/react';
import { Navigation, Pagination, Autoplay } from 'swiper/modules';
// Import Swiper styles
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';
const SwiperSlider = () => {
const cars = [
{ name: 'Tesla Model S - Available in Los Angeles', img: 'https://images.unsplash.com/photo-1560958089-b8a1929cea89?q=80&w=1000' },
{ name: 'Ford Mustang - Available in Las Vegas', img: 'https://images.unsplash.com/photo-1584345604476-8ec5e12e42dd?q=80&w=1000' },
{ name: 'Chevrolet Corvette - Available in Miami', img: 'https://images.unsplash.com/photo-1552519507-da3b142c6e3d?q=80&w=1000' },
];
return (
<div style={{ padding: '20px' }}>
<Swiper
modules={[Navigation, Pagination, Autoplay]}
spaceBetween={50}
slidesPerView={1}
navigation
pagination={{ clickable: true }}
autoplay={{ delay: 3000 }}
style={{ height: '400px', borderRadius: '15px' }}
>
{cars.map((car, index) => (
<SwiperSlide key={index}>
<div style={{ position: 'relative', height: '100%' }}>
<img
src={car.img}
alt={car.name}
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
/>
<div style={{
position: 'absolute',
bottom: '20px',
left: '20px',
color: 'white',
background: 'rgba(0,0,0,0.5)',
padding: '10px'
}}>
{car.name}
</div>
</div>
</SwiperSlide>
))}
</Swiper>
</div>
);
};
export default SwiperSlider;I love Swiper because it provides “out-of-the-box” features like autoplay and pagination. It saves a lot of time when the client wants a polished, high-end feel for their gallery.
Method 3: The Quick Way with React-Slick
For projects that require complex configurations, such as multiple rows or variable widths, React-Slick is my go-to.
It has been around for a long time and has a massive community behind it.
I used this library for a major e-commerce store based in Chicago to handle their product carousels.
First, install the necessary packages: npm install react-slick slick-carousel
import React from "react";
import Slider from "react-slick";
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
const SlickSlider = () => {
const settings = {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 3,
slidesToScroll: 1,
responsive: [
{
breakpoint: 1024,
settings: {
slidesToShow: 2,
}
},
{
breakpoint: 600,
settings: {
slidesToShow: 1,
}
}
]
};
const cities = [
{ city: "New York City", img: "https://images.unsplash.com/photo-1496442226666-8d4d0e62e6e9?q=80&w=1000" },
{ city: "Chicago", img: "https://images.unsplash.com/photo-1494522855154-9297ac14b55f?q=80&w=1000" },
{ city: "Seattle", img: "https://images.unsplash.com/photo-1502175353174-a7a70e73b362?q=80&w=1000" },
{ city: "Austin", img: "https://images.unsplash.com/photo-1531219572328-a0171b4448a3?q=80&w=1000" },
];
return (
<div style={{ width: "90%", margin: "0 auto" }}>
<h2> Top US Cities to Visit </h2>
<Slider {...settings}>
{cities.map((item, index) => (
<div key={index} style={{ padding: "10px" }}>
<img
src={item.img}
alt={item.city}
style={{ width: "100%", height: "200px", objectFit: "cover", borderRadius: "8px" }}
/>
<h4 style={{ textAlign: "center" }}>{item.city}</h4>
</div>
))}
</Slider>
</div>
);
};
export default SlickSlider;React-Slick is great for creating “card” sliders where you want to show multiple items at once. The responsive breakpoint settings make it very easy to adjust for different screen sizes.
Best Practices for Performance
When you build an image slider, performance is key. I always suggest lazy-loading images so they don’t slow down the initial page load.
You can use the loading=”lazy” attribute on your img tags or use a library that supports it. Another tip is to optimize your images using a service like Cloudinary or by converting them to WebP format.
Large, unoptimized images are the number one reason for slow React applications. Lastly, make sure your slider is accessible by adding aria-labels to your navigation buttons.
This ensures that users with screen readers can also enjoy the content you are providing. In this article, I have covered three distinct ways to implement a React image slider.
Depending on whether you need a simple custom solution or a feature-rich library, you can choose the method that fits best.
You may also like to read:
- How to Access React Context Outside of a Component
- How to Use Shadcn UI in React
- How to Pass Arguments to React Components
- React Hide Component Without Unmounting

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.