DEV Community

 Theodora Cristea
Theodora Cristea

Posted on

Build Your Own Infinite Carousel in React (with a Custom Hook)❗

Hey!🥰 It’s been a while since my last post…
No ofcorse, I haven’t quit web development,🙃 and nope, I didn’t go on a long vacation either.🙃 Quite the opposite - I’ve been coding non-stop, 6 out of 7 days. I’ve been busy with a project that I’ll share with you soon, but today I want to show you something smaller but really useful:

➤ How I built a reusable infinite carousel in React, using only a custom hook, a component, and some CSS.
GitHub: Carousel
Demo: Carousel


Why another carousel❓

Carousels are everywhere: online shops, landing pages, portfolios… and let’s be honest, many developers reach for a big library when all they need is a simple slider.

There’s nothing wrong with libraries, but sometimes it’s good to be curious and understand the logic behind them. Building one yourself gives you full control and help you creating your own mini-library.


What does an infinite carousel mean❓

A classic carousel has a beginning and an end. If you reach the last image and click “next,” it either stops or jumps back abruptly. An infinite carousel creates the illusion that the list never ends.
How❓

Clone a few slides and add them to the beginning and end.
When you move too far left or right, instantly reposition the list without the user noticing. This trick gives the user the feeling they can scroll endlessly.
Sounds a bit confusing❓Don’t worry, keep reading and it will all make sense.🥰


Project structure:

I split the logic into two parts:
InfiniteCarousel component ➤ handles the UI (images, titles, navigation buttons).
useCarousel hook ➤ handles the logic (clones, index, transitions, auto-slide, resize).
This makes the carousel reusable: you can drop the hook into any React project and use it with any type of content.


The useCarousel hook

The hook accepts a few configuration options:

useCarousel({
  visibleSlides: 4,           // how many slides are visible at once
  gap: 32,                    // spacing between them
  autoSlideInterval: 3000,    // autoplay interval in ms
});
Enter fullscreen mode Exit fullscreen mode

What it does under the hood

Index tracking: ➤ keeps track of the current position with a ref.
Transitions ➤ moves the carousel with translateX.
Invisible reset ➤ when you go past the edges, it disables transition, instantly repositions, then continues normally.
Auto-slide ➤ moves slides automatically, pauses on hover.
Resize handler ➤ recalculates slide widths when the window size changes.

The InfiniteCarousel component

The UI is quite straightforward:
• ul for the list of slides,
• li for each image,
• two buttons for manual navigation.


Responsive design

With some media queries, the carousel adapts to different screen sizes:
• On mobile → 1–2 slides visible,
• On tablet → 3 slides,
• On desktop → 4 slides.

@media screen and (min-width: 500px) {
  .li-right-tea {
    width: calc(50% - 32px / 2);
  }
}

@media screen and (min-width: 900px) {
  .li-right-tea {
    width: calc(33.33% - 64px / 3);
  }
}

@media screen and (min-width: 1200px) {
  .li-right-tea {
    width: calc(25% - 96px / 4);
  }
}
Enter fullscreen mode Exit fullscreen mode

Visual scheme of the logic

Let’s say we have 8 original slides: A B C D E F G H We want 4 visible at once ➤ that means we clone 4 at the beginning and 4 at the end.

Key positions:

Start (index = 4) ➤ aligned on the first real slide (A)
Visible: [ A | B | C | D ]
Going right (next):
You reach index 11 (H).
Next click ➤ index 12 (A clone).
➤ On transitionend, it instantly resets back to index 4 (A real).
Going left (prev):
You reach index 3 (H clone).
➤ On transitionend, it instantly resets back to index 11 (H real).
The user never sees the*jump* The illusion of infinity is preserved.


Final functionality

• Manual navigation with buttons,
• Auto-slide with customizable interval,
• Pause on hover,
• Invisible reset for infinite effect,
• Responsive (media queries + resize recalculation),
• Reusable (hook works with any type of content, not just images).


Conclusion❤️

Now you have a fully working infinite carousel in React, built from scratch, with no external libraries, and with full control over the behavior.🥰Of course, it can be enhanced with indicators (dots) for progress, animations, and other functionalities! I think building your own mini-libraries in React is worth it. You not only learn how things work under the hood, but you also get the freedom to extend and customize them however you like.

I hope this post helps you!🥰 For me, rewriting it was a great way to solidify my understanding. Let me know in the comments if you have questions or if this was useful for you.
Happy coding!


Top comments (16)

Collapse
 
hashbyt profile image
Hashbyt

This is such a well-explained tutorial! The way you handled transitions and the invisible reset for the infinite effect is super clever. I also appreciate how you made the carousel responsive with media queries and resize handling it’s a detail that’s often overlooked.

Quick question: how would you approach adding indicators (like dots) for progress? Would you integrate it into the hook or keep it as a separate component? Curious to hear your take!

Collapse
 
cristea_theodora_6200140b profile image
Theodora Cristea • Edited

I’m glad you like the functionality,🤗and I hope you understood the logic behind the carousel, it’s quite simple.
I tried hard to explain it in a way that would make sense both for beginners and for more advanced users.
When working with React, it’s recommended not to make components too long and to try separating them into smaller components for better site functionality, for reusability, clarity, and maintainability. I’m glad you’re adding the progress indicators functionality! 🙃I didn’t split everything into too many components or hooks so it would be easier to read, but of course, they can be separated!
I’m happy it’s helpful to you, happy coding!🤗

Collapse
 
yaldakhoshpey profile image
Yalda Khoshpey

nice 💪🏻❤️‍🔥😍

Collapse
 
cristea_theodora_6200140b profile image
Theodora Cristea

Thank you!😊

Collapse
 
yaldakhoshpey profile image
Yalda Khoshpey

❤️‍🔥⭐🤩

Collapse
 
yorgie7 profile image
Yogesh Bamanier

I loved under the hood functionalities. Keep doing and sharing 😇

Collapse
 
cristea_theodora_6200140b profile image
Theodora Cristea

Thank you! 🤗 I'm happy to hear that!

Collapse
 
uzzy412_73 profile image
Alexandru Ene

Hey, nice one! You made a good job on reusability. I think I might borrow it. With your permission, of course! :)

Collapse
 
cristea_theodora_6200140b profile image
Theodora Cristea

Thank you so much! Is not the perfect one, but is working🙃 I'm so glad to hear that! 🥰 You have my permission, of course!🤗 I hope will be helpful for you! Happy codding!🙃

Collapse
 
chandanpatidar profile image
Chandan Patidar

Wow great

Collapse
 
cristea_theodora_6200140b profile image
Theodora Cristea

Thank you so much!🤗

Collapse
 
dragostrif profile image
DragosTrif

Deployit with github pages

Collapse
 
cristea_theodora_6200140b profile image
Theodora Cristea

I will do it!😊Thank you!

Collapse
 
kc900201 profile image
KC

Thanks for sharing this. I'd like to borrow this code as well. What would you suggest to improve the code's performance?

Collapse
 
cristea_theodora_6200140b profile image
Theodora Cristea

You're welcome!🤗 I didn’t split the hook into smaller parts myself, but if you’d like to shorten it, you could simplify it into two hooks.
As for performance… I’m aware it’s not the perfect carousel, but for me it’s not about perfection, it’s about the learning process... I might create another one in the future or make improvements to this one to share here on DEV.😊

So, The first hook could handle navigation + index management - taking care of the index, the showNext and showPrev functions, and the resets when you reach the end of the original slides.

The second hook could handle autoSlide (interval + pause on hover) - managing only the interval and the pause/resume on hover logic.

Splitting the logic into two hooks would mainly help with clarity, reusability, and maintainability. Hope this helps! Happy coding!🤗

Collapse
 
yorgie7 profile image
Yogesh Bamanier

Seems your Discord link has expired...