Infinite scrolling carousel with hover effects using Framer Motion

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we are going to recreate this infinite scrolling Carousel from the Apple homepod product page and addition to being infinitely scrolling the carousel also has a really interesting hover effect where it slows down the scrolling speed so you can see here I'm hovering over some of the items and it slows down and when I take it off it goes back to the normal scrolling speed here is a quick demo of our version we're going to build it's a close replica of the Apple version we have an infinite scrolling Carousel and when we hover over any of the images we also have this nice slowdown of the carousel on Hover and we go off it resets the old scrolling speed to get started go ahead and download the starter code using the link in the description down below make sure to run mpm install to get all the dependencies and with that let's jump in here we have the starter code for the project is just a blank onepage website using nextjs and style with Tailwind a couple of things I want to just call out in the starter code before we jump in the first is I've already included a bunch of images in the public folder that you'll need for the project and I've also gone ahead and just brought them in to this array on the index page already for us and the second thing to call it as well is in the next config I have gone ahead and added a SVG loader for working with svgs more easily for us as we go through this project all right let's get started by first creating the content and structure of the image Carousel itself so I'll start just in this index file I'm first just going to collapse this images array so let's go and start with this main tag going to remove this placeholder content and inside this main tag I'm going to do a div here and then inside this div we are going to actually map over the images so let me quickly set that up so we'll say images do map and I'll take the item and the index here for the mapping we'll pass the item as a key and we'll end up passing in a custom component which will create in a second for the image cards but let's first style this Main and div tag so on this main tag I'm just going to add some vertical padding and then on this div I'm going to add a class of absolute left zero flex boox and a gap of four so this will lay out the images horizontally it's throwing an error currently because there's no jsx in here yet but what we're going to do is we're going to add a new component called the card component that we haven't created yet that will take the images and display them appropriately so let's just go ahead and quickly create that component now so I'm going to create a new folder for components and inside of here I'll create a new card. TSX file make a placeholder component for now so we can import it here the the errors all right and you can already see we have a list of horizontal card components here which just a card for now so nothing really that interesting all right let's go into the card component and build it out so the the first thing I'm going to set up are the props for this card that we need to put in so in this case it's just going to take each of these image URL strings as a property so let's set that up so up here I'll Define an interface called cart props and it'll simply just have one string value that we'll call image and then on this card component now we can set the type to be a react functional component which will take the card props and I'll destructure as well and then inside here we'll keep this div and inside of the div we'll add a next image tag which we'll bring in here and the source will be the image alt will be the image name we'll give it a fill property and then also apply a style of object fit should be cover and let me close off this tag as well so now we need to now notice is an error here in the home tag and that is because it's during an error saying missing properties so let's go ahead and pass the properties so we want the image property to take the value of item and let's also pass in a key here and it will just be the index here and I hit say we can't see anything yet this is because we still need to go and size the image appropriately so for that I'm going to go back to the card component and because we're saying this image should just fill its parent well the problem is we haven't defined yet what the size of this dip should be so let's go ahead and do that with some styling so I'm going to give this a class name relative overflow hidden height of 200 pixels A Min width of 200 pixels background of slate 400 rounded Excel and I'm also going to add a flex justify Center and item Center and the reason we're going to do that in a second is because we're going to add an overlay to this that we'll use for the hover effect so now if I hit save all right now we have this list of images they're nicely squared and rounded off as well all right so now let's go ahead and add the overlay here for this card now for this the first thing I'm going to do is I'm going to set up a state variable to track whether the hover should show or not the overlay so I'm going to say call this show overlay set show overlay equals you state and Neally it's just going to be false and let's import you state let me go ahead and close this as well and then what we're going to do is inside this div instead of directly just showing the image first I'm going to add a conditional showing here of some other stuff so we would say if show overlay is true then let's go ahead and return some of this other stuff as well so here I'm going to add a div and this div I'm just going to go ahead and add some styles to it now is going to be a position absolute inset of zero so the top bottom left and right will all be zero for the position absolute Z of 10 to make sure it shows up above everything else in this component Flex justify Center item Center all right so this is the container for the overlay now the different components of the overlay so there's going to be a couple the first is just going to be a semi-transparent black rectangle so let's go ahead and do that as just a self-closing div and in this div we're going to give it class name of absolute BG of black pointer events none which is going to be important capacity of 50 height of four and width of four and just so we can see this I'm just going to go ahead and set this state to true for now so we can see it and so now we can see this black overlay show up and now after this black overlay we are going to add some content here so it's going to be a H1 tag and in this H1 tag I'm going to add some classes here as well going to give it a BG of white font of semibold text small Z of 10 some vertical and horizontal padding rounded a full Flex items Center a gap of5 characters and on Hover I'm going to get this opacity of 75 so now we have this effect here so now inside of this H1 I'm going to provide a span and the span is just going to say explore now so now we can see the text shows up here and in addition to this expand I'm also going to add a arrow icon and so for that at the very top I'm going to import Arrow from and I'm going to go to the public folder and grab the arrow.svg and we can import it like this like a component because of that webpack loader that we had set earlier in the nextjs config file and so now down here underneath the span I'm simply going to say arrow and I'm going to give it a couple of class names so we can see it of height four and width for and I'm noticing right now the Gap isn't working and that's because I forgot the P here for Gap all right so this is the overlay finish so now let's go ahead and dynamically set up so it shows up on Hover only so I'm going to go ahead and set this to back to false for show overlay now for this we're going to use frame motion to drive all these animations so the first thing I'm going to do is actually convert this parent div to be a motion div and we're going to see why in a second we're going to do that make this a motion div and let's go ahead and import motion from PR motion and so now first thing we're going to do is I'm going to provide a onhover start which comes from frame motion and what we want to do when this happens is of course we want to set show overlay to be true and then on Hover n we want to set show overlay to be false so now if I go ahead and hover we get the overlay showing up when we hover over any of these images but now we actually want to animate this properly so let's go to this div here of the overlay let's make this a motion div as well and for this motion div we are going to set some of the properties so first I'm going to set initial so the prean animation starting state to be of opacity of zero we want to animate to pacity of one so we'll fade in spell that correctly and then we also going to add an exit animation so when this leaves we want it to fade out so go back to opacity of zero so just by doing that now if I hover it nicely fades in but if I remove the hover you can see it's not animating out as we want it to we'll get to that in a second why that's not working the other animation I want to add is actually for this H1 I want to add some vertical movement when it comes in so let me convert this into a motion H1 and then after that we're going to add again some of the frame or motion properties so the starting State for the loading animation will be y of 10 we want to animate to a y position of zero so it's intended position and on exit again we'll return it to Y of 10 so now we'll see when we hover we can see that the button this explore Now button actually comes up a little bit bounces up on the load now to get to appropriately animate out we need to add a animate presence around this entire overlay block so let me go ahead and do that so animate presence and it will end here and animate presence make shes to tell framer motion that it should keep track of when these items leave the Dom and therefore to animate them out as appropriate based on these exit properties so now if we hover and now remove okay now this animation seems to be working really nicely all right so that is all of the core content of the carousel that's done so now let's move on to getting the infinite scrolling working so for this I'm going to go back to the index file and let's first take a second to talk about the approach we're going to use for getting this infinite scrolling effect so effectively what we're going to do is we are going to take this list of images we have right now we are going to make a second copy of this same object and show it to the right so essentially have two copies of the image list showing this will make sure that when we get to the end of the list it will show the first one automatically because it's starting over again with a second copy but then what we'll do is once we confirm that the first true set of images has gone off the page we will in the background silently reset this entire container back to its original position so that it can start again from the beginning and move across from the beginning and it'll keep resetting over and over so let's jump into actually doing this so the first thing I'm going to do is I'm going to make a second copy of this array that we want to map over so here you can actually see this is why I did the Syntax for mapping is so I can just go here and say okay let's do another copy of images now we can't really see it because this second copy is off the page right now the next thing I want to do is I want to get the width of the image set and we are going to do this by using a hook called use measure which comes from a external library and we're going to use that to grab the width of this image set so I'm just going to go up here and right below this of images I'm going to say let ref and width which I'm going to extract out going to be use measure and use measure you can see we're importing from react use measure and so this gives us the width of the object which we have this ref and now we need to attach this ref of course to what we want to measure the width of and of course that will be this div here so I'm going to ahead and attach ref equals to ref so now we are going to create a motion value because we're use frame or motion again that will tell us how we should essentially move this image set to the left to get the scrolling effect so for that I'm going to go up here and we're going to say const by call X translation and we'll say use motion value and set initially a value of zero and then what we're going to do is go ahead and update the value of this as time progresses so to do that I'm going to go into a use effect and inside this use effect we are going to first create a variable called finished position or final position and what we're going to do is we're going to calculate essentially what is that final position we need this image set to scroll to before it needs to run that reset in the background essentially what that will mean is we want this to reset to happen when we get to the second copy of this array list when the first image pretty much exactly lines up where like this first image is right now that's when we want want to do the switch so we'll calculate this as minus width which is again the width that we have from up here divided by two because this two copies and minus 8 and this minus 8 is because of the gaps that we have currently between these images so now what we need to do is we need to animate this x translation or simulate its animation going forward so that it Scrolls smoothly this div so for that we're going to use animation controls from frame or motion so for that I'm going to actually Define a variable up here called controls and then down here I'm going to say controls is going to equal animate which comes from frame or motion and I'm going to say I want to animate X translation and I want to animate from zero to final position and I'm going to give some other properties here so I want to buy a ease of linear duration let's set the duration to be 25 repeat will be Infinity because we want it to infinitely repeat the repeat type will be Loop and repeat delay will be zero and then the other thing we just need to do is a couple of things so first for good hygiene we need to return controls. stop so this is the D structure of this controls object so when this page comes down we need to make sure we appropriately clean this up so it doesn't stay in memory and then finally on the use effect we need to pass in the array of dependencies and here dependencies we have r x translation and width all right so now we need to actually go ahead and attach this x translation value to the div so it actually ingests this styling so for that we need to convert this div to a motion div so it can accept a motion value as a property so motion div and then after this ref we're going to say style equals and for the x value will give it a value of x translation right so when I hit save look at that it is starting to move and it will keep moving and what we'll notice is when the first copy of the original list finishes we'll notice here in a second that it will seemingly reset in the background without anyone noticing so we're getting to that place now and yep so this is already reset actually in the background we didn't really even notice it and so we now have this infinite scrolling Behavior All right so the final piece that we want to add here is the hover effect where it slows down the speed of the scrolling so right now if we hover we just have this hover on each of the cards but we want to now add the Slowdown effect as well for the Carol speed so to do this let's go ahead and add first at the top here the different speeds essentially that we want this to run at so for this I'm going to go up here and I'm just going to Define first a a constant that we're going to call fast duration and we'll always set this to 25 we'll create a slow duration as well which is 75 and then I'll create a state variable here that will track which duration is effectively active so originally I'll take it the value of fast duration and then when I import you state what I'm going to quickly go do here as well is instead of passing 25 here directly I'm going to pass duration and I'm also going to add duration to the dependency array of the use effect so right now this won't change anything at all and now what we need to do is on this overall div we're going to add on Hover start and for this we're going to set duration to the slow duration and on Hover n I'm going to set duration to fast duration so now if I hover it's slowing but you can see this really weird effect that's going on right now where it seems like the whole image Carousel is resetting on Hover now why is this well it's actually because if we track what's going on here when we hover we're setting a new value for this duration State variable this duration State variable because it changes it triggers the use effect and when it triggers this use effect what happens is this control object gets recreated here because it gets recreated with a new duration value because it gets recreated though the original version gets destroyed because this control stop the new one gets created and that's what's get set as the active animation controls but it starts from scratch from an x transation value of zero so hence you have this resetting Behavior where it resets back to zero the scroll to deal with this what we need to do is add some additional tracking that says if we are in the middle of the scroll animation happening which is going to happen almost all the time we need to make sure we finish that animation first at the slower speed before we go and reset to this like new control object that starts from zero with the new animation speed to do this we're going to add some other state variables to track this so I'm just going to go down here and I'm going to say const and we're going to create one variable that we call must finish so this will essentially say we need to finish a animation that's in progress and this will start with a value of false and I'm also going to create one called rerender set rerender and this will also have a use state of false and what this render one is going to do here is it's essentially going to manually tell the Dom when we need to rerender essentially this entire thing and set the new animation control object so now what we'll do is in this use effect we're going to add some additional Logics so we're going to say if we need to finish an animation that's already started then we're going to do some stuff else we're actually going to do what we had before so I'm just going to move this into the lse statement and now because it's POS possibly undefined We'll add a question mark there for controls now what we need to do is for this must finish instead of setting the control object to be this what we defined down here we're going to select a slightly different version of this so here I'm going to say we're still going to animate X translation but instead of going from zero to final position we are going to go from the current value of x transation which I'm going to grab X transation doget to final position so finish the scrolling that you're already in the middle of doing and then for the options here I'm still going to apply a ease of linear the duration is going to be here the currently set duration but it's only going to be a fraction in that based on how much progress has already been done so here it's going to be 1 minus X translation. getet over final position so 1 minus the progress has already been made and then we're going to also pass the on complete call back this will be a function and when it completes I'm going to say set must finish to be false because we've completed now this intermediary animation so we don't do this again and set render to be not a render and this will force essentially this entire thing to kick off again and rerun and for that I'm just going to add a rerender down here as well as a dependency so that when render gets changed here it will Rick this off and rerun this use effect and at that point must finish false and it'll go back to setting this control object as the scroll so finally then what we need to do is down here in the onhover start and N we need to edit these and so because we're going to have multiple statements here need to go to the curly braces going to say here set must finish to be true so when the hover starts we need to make sure we finish the existing animation and then set the duration to be slow duration and then on Hover n we need to set must finish to be true again here because again it's switching so it needs to finish the existing animation before switching the duration and the object all right so now let's go ahead and try this so now if I hover it slows down and when I hover off it continues at this faster speed I'll do it again hover and it continues slows and continues slows and continues so now we have the proper handling of this this animation with that we finished trading this infinite Carousel if you have any questions feel free to drop them down in the comments below and on screen now is another video for you to check out and I'll see you in the next video
Info
Channel: Built With Code
Views: 10,166
Rating: undefined out of 5
Keywords: Built With Code, Coding, javascript, nextjs, next js tutorial, html, css, next.js, TailwindCSS, tailwind css react, tailwind css, tailwind, tailwind tutorial, typescript, website coding, framer motion tutorial, framer motion animation, infinite scroll carousel, framer motion infinite carousel, framer motion hover, infinite carousel next js, framer motion on hover, framer motion animatepresence, apple homepod, apple product page
Id: Ot4nZ6UjJLE
Channel Id: undefined
Length: 22min 40sec (1360 seconds)
Published: Mon Feb 12 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.