Infinite carousel with framer-motion

Koen Van Geert
3 min readMar 17, 2021

--

The Problem

While creating the app OneJournal, I wanted to provide swipe functionality for navigating between journal entries. This, however, posed a problem because the list of journal entries is infinite. I was using Framer Motion for other animations at the time and decided to create a carousel with this instead of using another library which would potentially increase the bundle size by more than implementing it myself.

Framer Motion provides a convenient set of primitives to build complex animations and by leveraging these primitives we can achieve an infinite carousel with very little code. The article is split up into three sections where we will gradually create this carousel.

  1. Defining the interface for our carousel
  2. Positioning the elements on the screen
  3. Adding drag behaviour.

If you are just interested in the final result, you can scroll to the bottom of the page to find the link to Codesandbox and Github.

VirtualizedPage

Interface

We will need to dynamically render the children based on the currently visible index and also the page to the left and right of this index. For this, we can use render props and pass along the index we want it to display. This is very similar to how React-window does it.

Now that we know what the interface will look like we can start thinking about creating the components. We will separate the problem into two different components.
One will be responsible for orchestrating everything and another one for rendering the child pages.

Positioning the different items in the carousel

Now that we have the basics laid out and the API is defined we can start working on positioning the different items or pages in the carousel.

For our simple use case, we will lay the pages right next to each other. This can be done by defining left and right on the page based on the index. Because overflowX is set to hidden on the parent, the page to the left and right will not be visible until we start dragging.

style={{
...pageStyle,
left: `${index * 100}%`,
right: `${index * 100}%`
}}
The positioning of elements on the screen, where pages with index -1 and 1 are not in the current viewport
Positioning elements on the screen

Add drag behaviour

To add the drag behaviour, we will need to keep all the items in sync with each other. Luckily framer-motion provides a hook to do just that calleduseMotionValue.

We now have something where you can drag the items but we still have a few problems to solve.

  1. The carousel only displays items with an index-1, 0, 1 and never updates.
  2. The carousel does not snap to the item when letting go

To achieve both of these requirements, we will need to update the current index and animate x to the correct value. For simplicity’s sake, we will update the index when the user drags the item more than 1/4 of the width of the container.

Wrapping up

By using the primitives provided by framer motion we can easily create our own version of a reusable carousel. This component is used for the journal overview, the calendar navigation and the image gallery inside the app.

You can find the final result here:
https://codesandbox.io/s/github/koenvg/infinite-carousel-with-framer-motion
https://github.com/koenvg/infinite-carousel-with-framer-motion

--

--

Koen Van Geert
Koen Van Geert

Written by Koen Van Geert

Full stack developer with a passion for the web

Responses (2)