So I've got this accordion-layout working with react-router-dom
using a rather unconventional markup structure.
Demo: https://codesandbox.io/s/falling-violet-kvqn2?file=/src/Case.js
Shortened code for one accordion header:
<motion.div
layout
transition={transition}
key={item.id}
style={{
flex: isActive ? 1 : 0,
flexBasis: isActive ? null : 56,
...
}}
>
<NavLink
style={{
...
}}
exact={true}
to={item.url}
/>
<Route exact path={item.url}>
<motion.div
transition={{ delay: 1, ...transition }}
variants={{
open: { opacity: 1 },
collapsed: { opacity: 0 }
}}
initial="collapsed"
animate="open"
exit="collapsed"
layout
style={{
...
}}
>
<Home />
</motion.div>
</Route>
</motion.div>
And I'm trying to get framer-motion
to animate between the accordion pages. Like in the gif below
You can see that it works fine to animate the in
transition. But struggles to animate the exit
prop on page change. Clicking on an accordion header, the content is abruptly hidden. Looks like it is being removed from the DOM without any consideration to AnimateSharedLayout
or AnimatePresence
. I tried adding in exitBeforeEnter
props but it doesn’t work.
Any ideas?
You will need to make some changes in your code:
Work with variants -> you can orchestration animations start: By default, all these animations will start simultaneously. But by using variants, we gain access to extra transition props like when, delayChildren, and staggerChildren that can let parents orchestrate the execution of child animations.
Also, looks like you will need to work with width
to change div sizes. I tried to do with flexBasis but i really couldnt do it, the transition just doesnt work.
Remove <Route>
as a "wrapper" of motion.div. It also stops the motion to do the animations/transitions.
Add <AnimatePresence>
as a wrapper of motion.div
children. You can check more here
So, my code looks like this:
I create this 2 variants:
const divVariants = {
expanded: {
width: "55%",
transition: {
duration: 1.2,
ease: [0.83, 0, 0.17, 1]
}
},
collapsed: {
width: "15%",
transition: {
duration: 1.2,
ease: [0.83, 0, 0.17, 1]
}
}
};
const tagVariants = {
show: {
opacity: 1,
transition: {
delay: 1,
duration: 1.2,
ease: [0.83, 0, 0.17, 1]
}
},
hidden: {
opacity: 0,
transition: {
duration: 1.2,
ease: [0.83, 0, 0.17, 1]
}
}
};
motion.div :
<!-- Parent -->
<motion.div
layout
variants={divVariants}
animate={isActive ? "expanded" : "collapsed"}
initial={false}
data-section={item.id}
key={item.id}
style={{
overflow: "hidden",
zIndex: i,
display: "flex",
position: "relative",
backgroundColor: `hsl(${i * 20},100%,50%)`
}}
>
<!-- Children -->
<AnimatePresence>
{isActive && (
<motion.div
layout
variants={tagVariants}
initial="hidden"
animate="show"
exit="hidden"
style={{
padding: 20,
maxWidth: "100%",
maxHeight: "100%",
width: "100%",
height: "100%",
overflowY: "hidden",
overflowX: "hidden"
}}
>
<Tag data={data} />
</motion.div>
)}
</AnimatePresence>
I also added some inline styles to all Cases:
<div
<!-- Avoid div to wrap when it is collapsing -->
style={{
whiteSpace: "nowrap",
overflow: "hidden"
}}
>
home 0
</div>
You can check the code here!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With