I am trying to create a mobile menu where the nav items fade in one at a time. I’ve dug around but can’t seem to find what I’m doing wrong here. Instead of staggering each NavLink item, they all load in at the same time.
Initially, I had thought maybe I should be using ‘delay’ instead of ‘delayChildren’ but that doesn’t seem to be the case.
mobileNav.tsx
'use client';
import { useState } from "react";
import {AnimatePresence, motion} from "framer-motion";
import NavLink from '@/components/nav/navLink';
const MobileNav = () => {
const [isOpen, setOpen] = useState<boolean>(false);
const handleClick = () => {
setOpen(!isOpen);
};
const menuVariants = {
closed: {
x: '100%',
},
open: {
x: 0,
transition: {
type: 'tween',
duration: 0.3,
},
},
};
const navLinksVariants = {
hidden: {},
visible: {
transition: {
staggerChildren: 0.1,
delayChildren: 0.3,
},
},
exit: {
transition: {
staggerChildren: 0.05,
staggerDirection: -1,
},
},
};
return(
<>
<AnimatePresence>
{isOpen &&
<motion.div className="z-10 w-screen h-screen bg-gray-500 absolute flex flex-col justify-center items-center"
variants={menuVariants}
initial="closed"
animate="open">
<motion.ul
variants={navLinksVariants}
initial="hidden"
animate="visible"
exit="exit">
<NavLink link="#projects">Projects</NavLink>
<NavLink link="#about">About</NavLink>
<NavLink link="#contact">Contact</NavLink>
</motion.ul>
</motion.div>
}
</AnimatePresence>
<button onClick={handleClick} className="p-4 flex flex-col justify-center items-center absolute z-20 lg:hidden">
{!isOpen &&
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-10">
<path strokeLinecap="round" strokeLinejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
</svg>
}
{isOpen &&
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-10">
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18 18 6M6 6l12 12" />
</svg>
}
</button>
</>
)
}
export default MobileNav;
navLink.tsx
'use client';
import { motion } from 'framer-motion';
interface NavLinkProps {
link: string;
children: string;
}
const NavLink: React.FC<NavLinkProps> = ({link, children}) => {
const linkItemVariants = {
hidden: { opacity: 0, y: '50%' },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.5,
ease: "easeOut" // Add ease-out easing function
},
},
exit: {
opacity: 0,
y: '80%',
transition: {
duration: 0.3,
ease: "easeOut" // Add ease-out easing function
}
},
};
return (
<motion.li className="lg:mx-5 sm:mb-5 text-5xl lg:text-lg"
variants={linkItemVariants}
initial="hidden"
animate="visible"
exit="exit">
<a href={link} aria-label={children}>
{children}
</a>
</motion.li>
);
};
export default NavLink;