Framer motion layout animation fails to account for page scrolling during transitions in NextJs routes

Currently, I am working on a fascinating NextJS project that showcases a series of interactive blocks. As the user navigates through the app, these blocks dynamically adjust their size and position on the screen.

To achieve this effect, I'm leveraging the power of framer-motion's layout feature. Everything works seamlessly except for one scenario: when users have scrolled down the page, it seems like framer-motion disregards the scroll position and animates the blocks from their original top-of-page location.

If you're curious to see this behavior in action, check out this interactive demo on codesandbox:

  1. Try selecting the first block without scrolling - notice how it animates flawlessly.
  2. Now, scroll all the way down and select the last block. You'll observe that instead of animating from its current viewport position, the block appears to animate from beneath the screen.

Is there a workaround to account for the scroll distance so that the animations are tied to the viewport's coordinates rather than the page's top? Your insight would be greatly appreciated!

For visual reference, take a look at this example:

Answer №1

It seems like the issue arises from changing routes, resulting in a smaller viewport for the new route. Although not ideal, one potential solution could involve saving the body height of the card list page and using it as the minimum height for the card detail page. This height adjustment can be removed once the layout animation is complete:

To implement this, begin by encapsulating the <Link> component within a custom wrapper called <CardRedirector>:

          <CardRedirector>
            <Link href={`/${card.id}`} scroll={false}>
              <p>{card.title}</p>
              <Block id={card.id} />
            </Link>
          </CardRedirector>

Within the <CardRedirector>, incorporate the use client hook to establish a click listener that saves the current body height as the minimum body height when the link is clicked:

"use client";

export const CardRedirector = ({ children }) => {
  const onCardClick = () => {
    const currentBodyHeight = document.body.scrollHeight;
    document.body.style.minHeight = `${currentBodyHeight}px`;
  };

  return <button onClick={onCardClick} style={{
    background: 'none',
    color: 'inherit',
    border: 'none',
    padding: '0',
    font: 'inherit',
    cursor: 'pointer',
    outline: 'inherit',
  }}>{children}</button>;
};

export default CardRedirector;

Next, on the card detail page, wrap the <Block> component with <BlockContainer> to leverage the use client hook and attach an event listener onLayoutAnimationComplete to remove the min-height property upon completion of the animation:

"use client";

import Block from "./block";

export const BlockContainer = ({ id }) => (
  <Block
    id={id}
    fixed="true"
    onLayoutAnimationComplete={() => {
      document.body.style.minHeight = "0";
    }}
  />
);

export default BlockContainer;

Finally, update the card detail page code as follows:

export const BlogPostPage = async ({ params }) => {
  const id = Number(params.slug);

  if (!id) return notFound();

  return (
    <>
      <BlockContainer id={id} />
      <Link href="/" scroll={false}>
        Back
      </Link>
    </>
  );
};

For the modified sandbox version, visit the following link:

https://codesandbox.io/p/devbox/next-js-with-framer-motion-example-forked-m7d5ss?layout=.......

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for adding new items to a Masonry Image List using React MUI

As I experiment with utilizing the React MUI Masonry Image List alongside the infinite scroll, I've found that they complement each other quite well. However, a challenge arises when appending new images to the Masonry image list. While I can success ...

How can we determine if a Node.js application will remain operational?

How is the longevity of a Node.js app determined? For example, consider this code snippet: console.log('Hello World'); In this case, the phrase will be printed and the app will exit immediately. However, with a web server that is actively lis ...

Selecting a particular item in a list depending on time using JavaScript, jQuery, or Angular

When working with a JSON file and binding it to list items, I have included a name/value pair in the json for each line indicating audio time, such as "time like 0, 5, 10 in seconds form". In my Cordova application, I am using a media plugin and implement ...

Using jQuery's slideToggle feature to hide content when clicked again or when a different button is

I have a challenge with creating toggle buttons that require specific functions: 1) Display content on the first click (this is working) 2) Conceal content when another button is clicked (this is also working) 3) Hide content on the second click (this i ...

The concept of undefined in JavaScript when an if condition is applied

In Node.js, there is a method used to handle API requests. An unusual behavior occurs when dealing with req.query.foo - even if it has a value defined, it becomes undefined when used in an if condition as shown below. Additionally, another req.query.foo ...

Customize checkbox and label using jQuery

I have a scenario where I have multiple checkboxes and corresponding labels. When the answer is correct, I want to change the background color of the selected checkbox and label. <input type="checkbox" id="a" class="check-with-label" /> <label fo ...

Issues arising from utilizing Twitter Bootstrap 3.1.x, the box-sizing property, and Revolution Slider

I'm currently working on a PyroCMS theme that is built with Twitter Bootstrap 3.1.x and includes Revolution Slider. However, I've encountered an issue where the property box-sizing: border-box; creates an unwanted grey border as shown in the imag ...

Trying to utilize RegEx for my project, but feeling stuck on how to solve my problem

^\d{1,12}$|(?=^.{1,15}$)^\d+\.\d{1,2}$ This is the current regular expression I am using. I need to adjust the maximum limit to 100,000,000,000 with an option for two decimal places. Additionally, I would like users to be able to inpu ...

Is there a way to ensure the content of two divs remains aligned despite changing data within them?

Currently, I have two separate Divs - one displaying temperature data and the other showing humidity levels. <div class="weatherwrap"> <div class="tempwrap" title="Current Temperature"> ...

Clicking on text triggers image display

My journey in coding is just starting and I have a good understanding of the basics of HTML, CSS, Javascript, and jQuery. I am trying to make an image appear when I click on text but struggling with the implementation. I'm working on a restaurant web ...

Receive a response in fragments from express on the browser

As I work on creating a progress bar to track long-running server-side tasks that may take up to a few minutes, I am exploring different methods to display the progress of each task. While WebSockets and interval polling are options, I prefer using long-po ...

Increasing and decreasing the display of content using JQuery based on height rather than character count

I'm attempting to create a show more/show less link with a set height of 200px that, when clicked, will reveal the rest of the content. Anything exceeding 200px will be hidden, and there will be a "show more" link to display the remaining text. I&apos ...

Having trouble with moving the svg:svg element?

I'm struggling to move an svg element that is nested within another svg. I am trying to directly manipulate the x and y values, but I keep encountering a "read-only" error. I attempted to use transform instead, but it doesn't seem to have any eff ...

How does SWR affect React state changes and component re-rendering?

I am currently utilizing SWR for data fetching as outlined in the documentation: function App () { const [pageIndex, setPageIndex] = useState(0); // The API URL incorporates the page index, which is a React state. const { data } = useSWR(`/api/data? ...

Guide to making two text boxes with SimpleDialog in jQuery Mobile

I came across the link below, but unfortunately it's not working for me. jQuery Mobile SimpleDialog with two Inputs? Is there anyone who can assist me after reviewing the code snippet provided below? <script type="text/javascript> ...

Twice the clicking actions triggered by the event

Whenever I try to trigger a function by clicking on the label text, the click event seems to be firing twice. HTML <label class="label_one"> Label One <input type="checkbox"/> </label> However, if I modify the HTML code as f ...

Troubleshooting Date Errors in Typescript with VueJS

Encountering a peculiar issue with Typescript while attempting to instantiate a new Date object. <template> <div> Testing Date</div> </template> <script lang="ts"> import Vue from "vue"; export default Vue.extend({ name: ...

JavaScript API for Outlook appointment object

Is there a way to change the appointment busy status "show as" to out of office using JavaScript in an Outlook web add-in? Also, how can I alter the value of all day event to true (tick it) using JavaScript in an Outlook web add-in? Any insights would be ...

"Utilize Selenium to navigate and select a menu option with a

In my dropdown menu, I am trying to use Selenium to move the mouse to the Documentation menu item and click on the App Configuration option within it. The mouse hover function is working properly, but I am unable to click on the App Configuration element. ...

The output of server.address() method in Node.js is ::

My memory serves me right, a few days back it was showing "localhost". I'm puzzled as to what altered server.address().address to now return double colons (::). According to my research, it seems to be returning an IPv6 address (::) because it's ...