0

I am trying to make a hamburger dropdown with animations on each of the menu options. Unfortunately, I have a problem with the exit animation.

I don't know how should I implement it, but what is happening is that my main navigation component - Navbar2 - has a few children of class MenuOption. I am setting a menuOpened property with true/false depending on whether the user opened the hamburger menu.

When the user opens the dropdown, MenuOption's animation runs well (open variant). Now, the issue is when the user closes it - I guess what is happening is the MenuOption component re-renders, completely omitting the exit animation (closed variant).

How can I make the MenuOption components run the exit animation without re-rendering those components?

Here is the code:

 const Navbar2 = () => {
 const [menuVisible, setMenuVisible] = useState(false);
 
 
 const variantsMenuDropdown = {
 closed: {
 height: ["150px", "150px", "0px"],
 },
 open: {
 height: ["0px", "150px"],
 },
 };
 
 
 return (
 <motion.div
 className="fixed z-50 w-full bg-white overflow-hidden"
 >
 <nav className="grid grid-cols-3 place-items-center pl-2 pr-2 ">
 <div
 onClick={() => {
 setMenuVisible(!menuVisible);
 }}
 >
 <HamburgerIcon className="justify-self-start" menuVisible={menuVisible} />
 </div>
 
 </nav>
 
 <motion.div
 animate={menuVisible ? "open" : "closed"}
 variants={variantsMenuDropdown}
 transition={{ duration: 0.30 }}
 className="bg-stone-50 w-full h-auto grid grid-rows-3 grid-cols-1 justify-items-start overflow-hidden pl-10 "
 >
 <div className="w-full h-auto bg-stone-50 p-1 flex items-center justify-start pl-10">
 <div onClick={() => setMenuVisible(!menuVisible)}>
 <MenuOption linkName={"Shop"} menuOpened={menuVisible} delayAnimation={0.03} />
 </div>
 </div>
 
 <div className="w-full h-auto bg-stone-50 p-1 flex items-center justify-start pl-10">
 <div onClick={() => setMenuVisible(!menuVisible)}>
 <MenuOption linkName={"About"} menuOpened={menuVisible} delayAnimation={0.06} />
 </div>
 </div>
 <div className="w-full h-auto bg-stone-50 p-1 flex items-center justify-start pl-10">
 <div onClick={() => setMenuVisible(!menuVisible)}>
 <MenuOption linkName={"Contact"} menuOpened={menuVisible} delayAnimation={0.09} />
 </div>
 </div>
 </motion.div>
 </motion.div>
 );
 };
 
 export default Navbar2;
 
 // MenuOption file
 import { useState } from "react";
 import { motion } from "motion/react";
 import { Link } from "react-router-dom";
 
 const MenuOption = ({ linkName, menuOpened, delayAnimation }) => {
 const [hovered, setHovered] = useState(false);
 
 const variantsText = {
 closed: {
 opacity: 0,
 x: [-3],
 },
 open: {
 x: [-3, -3, 5],
 opacity: 1
 }
 }
 
 return (
 <motion.div className="flex flex-col" onHoverStart={() => setHovered(true)} onHoverEnd={() => setHovered(false)}>
 <motion.div
 variants={variantsText}
 initial="preMount"
 animate={menuOpened ? "open" : "closed"}
 transition={{ duration: 0.50, delay: delayAnimation }}
 >
 <Link
 to={`/${linkName}`}
 className="relative text-black flex items-center group"
 >
 {linkName}
 </Link>
 <div className={`border-t-[1px] border-sky-600 rounded-xl transition-all duration-150 ease-in-out ${hovered ? 'w-full' : 'w-0'}`}></div>
 </motion.div>
 
 </motion.div>
 )
 }
 
 export default MenuOption;
T3 H40
2,9238 gold badges45 silver badges57 bronze badges
asked Oct 21, 2025 at 22:24

1 Answer 1

1

I've fixed this - the issue wasn't re-rendering but much more trivial.
Here, the "closed" animation only had one keyframe (so it automatically jumped to that time frame of x: -3 wihout slowly moving there. Hope it helps someone :)

Cheers!

 const variantsText = {
 closed: {
 opacity: 0,
 
 x: [-3], // <== change this to x:[5,-3]
 },
 open: {
 x: [-3, -3, 5],
 opacity: 1
 }
 }
answered Oct 22, 2025 at 7:29
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.