Closed maurocolella closed 8 months ago
yo I also have this issue in Next js . I solved it for my first time use but , I deleted that animation . Now I want to enable in next js and issue happening .
Hi there, that source code link isnβt working for me. Please reopen with a sandbox or repo
@mattgperry was private, sorry.
Here is the sandbox:
That is weird although I think I have them working here https://codesandbox.io/p/sandbox/charming-pine-zz12kx
When I've got a bit more time I can look into this, there's definietly something different about Next 13
Thanks a lot @mattgperry . It's early days for this project, and it's going to undergo some changes (maybe Remix, some css tweaks, and I will definitely lose the cheerio parsing once I connect it with a CMS back-end), but I thought I'd raise it as an edge case.
I am not blocked by all means, and if I figure out why it's working this way I'll be happy to share back.
Appreciate the help.
Hey folks, I'm running into the same issue here. I'm not sure how to even wrap AnimatePresence
in NextJs's new App directory because it's throwing all kinds of issues. I'm combining it with styled-components
and seems like there's some stuff that's happening there too.
Here's how I've currently implemented my layout.js
:
'use client'
import { AnimatePresence } from 'framer-motion'
import { GridOverlay } from '../components/GridOverlay'
import Header from '../components/Header'
import StyledComponentsRegistry from './styles/Registry'
import { ThemeContext } from './styles/ThemeContext'
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<StyledComponentsRegistry>
<ThemeContext>
<AnimatePresence mode="popLayout">
<GridOverlay />
<Header />
{children}
</AnimatePresence>
</ThemeContext>
</StyledComponentsRegistry>
</body>
</html>
)
}
One of the biggest errors I'm getting is:
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
Check the render method of `PopChild`.
at OuterLayoutRouter (webpack-internal:///./node_modules/next/dist/client/components/layout-router.js:18:11)
at PopChildMeasure (webpack-internal:///./node_modules/framer-motion/dist/es/components/AnimatePresence/PopChild.mjs:13:1)
at PopChild (webpack-internal:///./node_modules/framer-motion/dist/es/components/AnimatePresence/PopChild.mjs:33:21)
at PresenceChild (webpack-internal:///./node_modules/framer-motion/dist/es/components/AnimatePresence/PresenceChild.mjs:15:26)
at AnimatePresence (webpack-internal:///./node_modules/framer-motion/dist/es/components/AnimatePresence/index.mjs:72:28)
at Fe (webpack-internal:///./node_modules/styled-components/dist/styled-components.browser.esm.js:30:17299)
at ThemeContext (webpack-internal:///./app/styles/ThemeContext.js:16:11)
at StyledComponentsRegistry (webpack-internal:///./app/styles/Registry.js:19:11)
at body
at html
at RootLayout (webpack-internal:///./app/layout.jsx:18:11)
at ReactDevOverlay (webpack-internal:///./node_modules/next/dist/client/components/react-dev-overlay/internal/ReactDevOverlay.js:53:9)
at HotReload (webpack-internal:///./node_modules/next/dist/client/components/react-dev-overlay/hot-reloader-client.js:19:11)
at Router (webpack-internal:///./node_modules/next/dist/client/components/app-router.js:96:11)
at ErrorBoundaryHandler (webpack-internal:///./node_modules/next/dist/client/components/error-boundary.js:28:9)
at ErrorBoundary (webpack-internal:///./node_modules/next/dist/client/components/error-boundary.js:40:11)
at AppRouter
at ServerRoot (webpack-internal:///./node_modules/next/dist/client/app-index.js:113:11)
at RSCComponent
at Root (webpack-internal:///./node_modules/next/dist/client/app-index.js:130:11)
That is weird although I think I have them working here https://codesandbox.io/p/sandbox/charming-pine-zz12kx
Your example uses the pages
directory. @maurocolella uses the new /app
directory: https://beta.nextjs.org/docs. While still experimental it's definitely the new way of creating Next apps.
There are seemingly a couple of issues with transitions. Most notable: the exit animations do not work (see video). I'm not sure whether the issue is with Framer or with Next. Next does seem to unmount the layout immediately upon navigation. I've tried adding usePresence
to allow Framer to remove an element after a timeout but even that doesn't work.
The props on the component doing the transition are:
initial={{ opacity: 0, x: 100 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: 100 }}
transition={{ duration: 2 }}
key={pathname}
https://user-images.githubusercontent.com/6362631/213143210-634ce3fc-49ad-4135-b92a-9b1fe8aaa88d.mov
Per https://github.com/framer/motion/discussions/1775#discussioncomment-4299578 I have also tried using a template.tsx
file but that doesn't seem to work either, even though the Next docs specifically mention transitions to be a use-case for it: https://beta.nextjs.org/docs/routing/pages-and-layouts#templates.
Worth noting that I have organized my client/server components in a peculiar way to work around apparent bundling issues.
This is related to cheerio as mentioned (which I will drop soon).
That being said, I don't think I am working against either framework, and I might raise an issue with the Next team for their feedback.
On Wed, Jan 18, 2023, 6:20 PM Mike Ekkel @.***> wrote:
Per #1775 (reply in thread) https://github.com/framer/motion/discussions/1775#discussioncomment-4299578 I have also tried using a template.tsx file but that doesn't seem to work either, even though the Next docs specifically mention transitions to be a use-case for it: https://beta.nextjs.org/docs/routing/pages-and-layouts#templates.
β Reply to this email directly, view it on GitHub https://github.com/framer/motion/issues/1850#issuecomment-1386815010, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFZ7NBNFOOSD6OXYA5ZNQDWS67YFANCNFSM6AAAAAATJVFL2I . You are receiving this because you were mentioned.Message ID: @.***>
I have the same kind of issue in the Next 13. The Animate Presence is unable to freeze the exiting (children) component.
In the Root Layout, which is a server component, I have this:
In Main (client component) I have this:
In Inner (client component as well):
I added Freeze(react-freeze) as a workaround, but I don't like it.
It seems that both (the new component + the existing one) point somehow to the same component.
It seems that both (the new component + the existing one) point somehow to the same component.
This is, presumably, solved using template.js
(see: https://beta.nextjs.org/docs/routing/pages-and-layouts#templates). From the docs:
...routes that share a template, a new instance of the component is mounted, DOM elements are recreated...
After reading the Next.js v13 docs regarding the new Templates feature, I tried it out to house page-transition Framer Motion code.
Unfortunately the exit animation does not work (it's just completely ignored).
This is the file that contains my page-transition code.
Also see my template.tsx and layout.tsx file for more context.
Another finding: When using <AnimatePresence>
in template.tsx, the onExitComplete()
does not fire.
@Murkrage Some time ago I tried to use template.js but it didn't work. i will try again.
@jasonkylefrank For me the exit animation works. Try to wrap your motion.div into another component (client component). For that component provide key=pathname as you do. See my structure here: https://github.com/framer/motion/issues/1850#issuecomment-1418031574
in the inner component please use:
const [isPresent, safeToRemove] = usePresence();
My next js version: ^13.1.7-canary.4
Now, the problem is that the old component and the new one are pointing to the same instance (they are the same component). I also find that the old component sometimes it doesn't get unmounted.
I have it working for like 90%. The animation on Exit is or too fast loading animate-in or the exit is is too fast or too slow. The exit and enter works... but still works better using "pages" instead of the new "app" directory.
layout.tsx:
"use client";
import "@styles/globals.css";
import { anton, roboto } from "lib/fonts";
import { Footer, MainNavigation, MaxWidthWrapper } from "@components/ui";
import { AnalyticsWrapper, DefaultHead } from "@components/shared";
import Newsletter from "@components/sections/Newsletter";
import { AnimatePresence, motion } from "framer-motion";
import { usePathname } from "next/navigation";
export default function RootLayout({
children
}: {
children: React.ReactNode;
}) {
const pathname = usePathname();
return (
<html lang="en" className={`${anton.variable} ${roboto.variable}`}>
<DefaultHead />
<body className="min-h-screen text-gray-100 bg-midnight">
<MainNavigation />
<MaxWidthWrapper type="main">
<AnimatePresence
mode="wait"
initial={false}
onExitComplete={() => window.scrollTo(0, 0)}
>
<motion.div
key={pathname}
initial={{ opacity: 0, y: 25 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 25 }}
transition={{
type: "spring",
stiffness: 140,
damping: 20
}}
>
{children}
</motion.div>
</AnimatePresence>
</MaxWidthWrapper>
<AnalyticsWrapper />
<Newsletter />
<Footer />
</body>
</html>
);
}
I got exit animation to work using appDir
(13.2.2-canary1). template.tsx
is a lie, so ignore that until they fix it.
What you want to do is in your layout.tsx
(which is ideally rsc
), wrap a Client
component around your {children}
and have that be wrapped in the <AnimatePresence>
component.
// client.tsx
'use client'
import { motion, AnimatePresence } from 'framer-motion'
import { usePathname } from 'next/navigation'
// Client wraps any client/rsc components with AnimatePresence
export default function Client({children}: { children: ReactNode}) {
const pathname = usePathname()
return <AnimatePresence mode='wait' onExitComplete={doYourThing}>
<motion.div key={pathname}
initial={{}}
animate={{}}
exit={{}}
>
{children}
</motion.div>
</AnimatePresence>
}
// layout.tsx, this should ideally be `rsc`, so don't use `use client`
import Client from './client'
export default function Layout({children}: { children: ReactNode}) {
return <Client>{children}</Client>
}
@khuezy in my instance pathname
falls into an infinite loop and no route change happens
@beamercola hmm, what does your app structure look like? My solution is a hack until they fix template.tsx
.
@khuezy What is your framer-motion version? I still didn't manage to solve this issue. I am using Next 13.2.2-canary1 and framer-motion: ^10.0.1. I did exactly what you did.
@dumbravaandrei22 I'm using 9.0.3, I'll update to latest and let you know. Although the example above gets exit animations to work, the current problem is that nextjs replaces the contents before the exit animation plays. I believe once Vercel
fixes template.tsx
, it will behave correctly.
Edit: 10.0.1 exit animations work, but the premature navigation is still a problem. Lee from Vercel is aware of it so maybe it's on their plate.
Understood! Thank you!
@khuezy I tried this: https://github.com/framer/motion/issues/1850#issuecomment-1418031574. Is working, but it seems that the loading UI has a delay.
Ah I see, sorry missed your comment up there. We have the exact same problem.
@khuezy Indeed, np. Should we file a new bug to NextJs? Or do you track a relevant bug related to this issue on the Vercel side?
I haven't found a related ticket on the nextjs repo. Maybe we can create w/ some a minimal repro?
Yes, I will put it on my list. I will link the bug here.
It does work but you have to be a bit creative with it. Here's my solution.
// LayoutAnimatePresence.tsx
'use client'
import { AnimatePresence } from 'framer-motion'
import { usePathname } from 'next/navigation'
import { Fragment, type PropsWithChildren } from 'react'
export default function LayoutAnimatePresence({ children }: PropsWithChildren) {
const pathname = usePathname()
return (
<AnimatePresence initial={false} mode="wait">
<Fragment key={pathname}>{children}</Fragment>
</AnimatePresence>
)
}
// layout.tsx
import type { PropsWithChildren } from "react"
export default function RootLayout({ children }: PropsWithChildren) {
return (
<html lang="en">
<body>
<LayoutAnimatePresence>{children}</LayoutAnimatePresence>
</body>
</html>
)
}
@akashlama1998-icloud is the mode=wait required? Also, where do you provide the animation props?
@akashlama1998-icloud I tried your solution, and it works only in the page directory.
@dumbravaandrei22 Updated code for LayoutAnimatePresence wrapper component for Next.js 13.
// LayoutAnimatePresence.tsx
'use client'
import { AnimatePresence, AnimatePresenceProps } from 'framer-motion'
import { usePathname } from 'next/navigation'
import { Fragment, type PropsWithChildren } from 'react'
export default function LayoutAnimatePresence({
children,
...restProps
}: PropsWithChildren<AnimatePresenceProps>) {
const pathname = usePathname()
return (
<AnimatePresence {...restProps}>
<Fragment key={pathname}>{children}</Fragment>
</AnimatePresence>
)
}
@NacereddineRebouh You're right! I was about to post this it seems like exit animations still doesn't work inside the new app directory if wrapped around to the whole children layout. May be any update by @mattgperry
@akashlama1998-icloud a few minutes ago, I had the onExitAnimation fire, and the pages console log when unmounting, but still, the exit animation does not work; I even tried using template.tsx. something weird is happening with nextjs. I had two pages: /page1 and /page2 -each one with a use effect that console log a message when mounting and unmounting -I used your LayoutAnimatePresence in Layout.tsx, -and I had a Header with Two Link tags to page1 and page2 here's what I had in the console: page 1 mounted LayoutAnimatePresence mounted navigating to Page2....... page 1 unmounting page 2 mounted
everything works as expected but the exitAnimation.
@NacereddineRebouh Yes the same thing is happening with me.. till the bug is reviewed and fixed I shifted my whole project to the old way using pages directory.. @mattgperry is the only faith and hope I have now.. π₯²
I also give a try on the new app folder and indeed I have trouble with the exit animation, it just don't work in the new App even with the template.js and separate it as a client component, however, in the pages folder it works fine.
Here's a minimal reproducing example for @khuezy's approach which shows bad exit-behaviour: https://github.com/okybr/mre-next13-appdir-framer-motion
Wow, four months in and still not a fix. Next.js devs are sleeping.
Hi i have the same problem in Next 13. The exit animation not work if the AnimatePresence component is in the layout root component
+1 same problem, would love to see a fix for exit animations, tried on latest Next canary release (13.3.2-canary.6) and still not working
also can't get it to work, it's a shame because the latest version of Next.js is very easy to use
Not sure if it's a Framer motion or Next issue at this point though π
Any updates on this? In the latest versions of framer motion 10.12.4
and next 13.3.2-canary.12
, the exit
animation is working, but the premature navigation that @khuezy mentioned is still happening, which causes a weird flash of the next page's content before the animation's trigger:
https://share.cleanshot.com/KmksdBxN
That being said I'm still using layout.tsx
. If switching to template.tsx
, do we lose all the benefits of SSR? Or will the page.tsx
still be SSR'd, and only the root layout misses that?
as a follow-up to the above, I tested switching to using template.tsx
and the exit
animation no longer works
Any updates on this from anyone? Would be helpful...
It looks like appDir is stable as of 13.4 today. Looking forward to getting a fix on this soon
Is there also an issue for this open somewhere on Nextjs's repo or is this suposed to stay on the framer repo?
@SchmidtDavid I am sorry I didn't follow up with Next.js/Vercel in part because the app directory was in rapid flux/beta at that time. There were several known instabilities and incompatibilities with the wider React ecosystem.
I was hoping that the framer motion team (@mattgperry ) would have more direct channels & bandwidth to look into it.
That said, given the traction this has gained, and that the app directory is emerging/has emerged from beta, I am more than happy to follow up.
Here. I have filed a bug with Next.js.
In the meantime, for some of these scenarios, a possible workaround is to simply use CSS transitions, or the gorgeous view transitions now available in Chrome.
Thank you maurocolella for this great idea, could you please provide more details about your proposal? Like adding CSS classes with effects is that your idea? And why does the patterns-view transitions doesn't work in all browsers? How to use it with next?
@Dimitri-Jacquin all the effects that can be achieved using Framer Motion build up on underlying APIs, like CSS transitions yes or CSS animations, or the Web Animations API.
So any of these solutions can be used to work around the temporary misalignment between Framer Motion and Next.js. I am sure you can find tutorials for any of them easily for quite a large number of effects.
As for view transitions, it's a relatively new API in the exploratory stages. It has yet to become a standard, but it's on the way. The article I linked has details about how to use it with Next.js. Just scroll down under the React section, although you can find other great tutorials for that as well.
1. Read the FAQs π
2. Describe the bug
With Next 13, using separation between server and client components, shared layout animations don't work when implementing the seemingly trivial navigation menu underline. Using either the deprecated or the modern approach (ie.
layoutId
on the target components).3. IMPORTANT: Provide a CodeSandbox reproduction of the bug
This issue could be heavily dependent upon styles and nesting(s). The structure honors HTML and React semantics, but it runs complex animations. Hence: the repro is complete, interactive, commentable and with full source code.
Live: https://portfolio-2023-git-feature-implement-layout-maurocolella.vercel.app/
Implementation: https://github.com/maurocolella/portfolio_2023/pull/2/files#diff-f7c999b982bfdbf5f3790e5b148e2343ffb7611b9ba579756dabab9fc76cb2e7
4. Steps to reproduce
On the example page: https://portfolio-2023-git-feature-implement-layout-maurocolella.vercel.app/
Simply click navigation items. Transition doesn't take place.
5. Expected behavior
I would expect a smooth transition to occur as in the examples.
6. Video or screenshots
N/A.
7. Environment details
Ubuntu Linux 20.04, Chrome beta, Chrome stable, Firefox.
FAQs
Framer Motion won't install
Framer Motion 7+ uses React 18 as a minimum. If you can't upgrade React, install the latest version of Framer Motion 6.
height: "auto"
is jumpingAnimating to/from
auto
requires measuring the DOM. There's no perfect way to do this and if you have also applied padding to the same element, these measurements might be wrong.The recommended solution is to move padding to a child element. See this issue for the full discussion.
Type error with
AnimateSharedLayout
AnimateSharedLayout
was deprecated in 5.0. Refer to the upgrade guide for instructions on how to remove.Preact isn't working
Framer Motion isn't compatible with Preact.
AnimatePresence
isn't workingHave all of its immediate children got a unique
key
prop that remains the same for that component every render?Is the
AnimatePresence
correctly outside of the controlling conditional?AnimatePresence
must be rendered whenever you expect anexit
animation to run - it can't do so if it's unmounted!