40
loading...
This website collects cookies to deliver better user experience
// _app.tsx
function MyApp({ Component, pageProps, router }: AppProps) {
return (
<div className="app-wrap">
<LazyMotion features={domAnimation}>
<AnimatePresence exitBeforeEnter>
<m.div
key={router.route.concat(animation.name)}
className="page-wrap"
initial="initial"
animate="animate"
exit="exit"
variants={animation.variants}
transition={animation.transition}
>
<Component {...pageProps} />
</m.div>
</AnimatePresence>
</LazyMotion>
</div>
)
}
LazyMotion
component, instead of regular Motion
component, this is just for reducing the size of the bundle. Framer is not a small library_app
component, which is the main component in the framework, everything that is imported there, will be bundled in the initial bundle downloadWhen you build the project this is indicated by the First Load JS shared by all
item in the Next.js build report.
LazyMotion
will not slice the size of the bundle by much (around 5-7kb) but why not use it when it's available. Also, the folks that support FramerYou will notice that we are using features={domAnimation}
on the LazyMotion
component which means that we are only bundling a subset of Framer functionality. Things like pan and drag gestures and layout animations will not be available. Check out the official documention for the component to know more.
AnimatePresence
component is used for animating child components when they are removed from the React tree. ItexitBeforeEnter
, it allows Framer to animate one component at a time.Component
in this whole setup, after a route change will animate out and then the new page (which is also a Component
) will animate in. So there will be no overlap and we only get to see one page at any given time.exitBeforeEnter
is set to false. When this property is false
it will enable animations on both pages (new and old at the same time). Make sure to enable the "overlap page transitions" checkbox.Motion
and m
components are the main building blocks for Framer animations. Anything you want animated should go inside these components.m.div
component is very similar to regular Framer Motion
component. It is an optimized version that works in tandem with LazyMotion
.
m
component can be used in the same way as Motion
, but it comes with no features preloaded. These are then provided by LazyMotion
.labels
functionality of Framer to animate the components. Take a look at this basic example, it will animate ComponentToAnimate
opacity from 0 to 1 and then back to 0.function MyApp() {
return (
<m.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.7 }}
>
<ComponentToAnimate />
</m.div>
)
}
initial
- How the element should look when the element is mounted into the React tree (before the animation starts)animate
- How it should look when the animation ends (basically when it's animated into position)exit
- How it should look when it's
animated out (just before it's removed from the React tree )transition
- how will the actual animation behave duration, easing, etc. It is similar to the css
transitions property.m.div
componentvariants
- this will allow us to organize animations as objects, and refer to them by name, and switch between them on demand.const myAnimation = {
initial: {
opacity: 0
},
animate: {
opacity: 1
},
exit: {
opacity: 0
},
transition: {
duration: 0.7
}
}
function Component() {
return (
<m.div
initial="initial"
animate="animate"
exit="exit"
transition={myAnimation.transition}
variants={myAnimation}
/>
)
}
variants
property (myAnimation). In the demo, we are doing this via the HTML dropdown elements and simple useState
hook. You can refer to the animations.ts
file to see all the animations that are used in the demo// animations.ts excerp
const slideUp = {
name: 'Slide Up',
variants: {
initial: {
opacity: 0,
top: '100vh',
scale: 0.4
},
animate: {
opacity: 1,
top: '0vh',
scale: 1
},
exit: {
opacity: 0,
top: '100vh',
scale: 0.4
}
},
transition: {
duration: 0.7
}
}
const slideRight = {
name: 'Slide Right',
variants: {
initial: {
opacity: 0,
left: '-100%',
scale: 0.6
},
animate: {
opacity: 1,
left: 0,
scale: 1
},
exit: {
opacity: 0,
left: '100%',
scale: 0.6
}
},
transition: {
duration: 0.7
}
}