Search code examples
reactjsnext.jsframer-motion

How to use stagger from framer-motion


Want to use stagger to animate buttons one by one using animations as components, but buttons are still animated together

transition.tsx:

const section = {
    hidden: { scale: 0, opacity: 0, x: 0, y: 20 },
    animate: {
        scale: 1,
        opacity: 1,
        x: 0,
        y: 0,
        transition: {
            staggerChildren: 0.2,
        },
    },
};

export const SectionTransition = ({
    children,
}: {
    children: React.ReactNode;
}) => {
    return (
        <AnimatePresence mode="wait">
            <motion.div
                animate="enter"
                variants={section}
                className="overflow-hidden"
            >
                <motion.div variants={section}>{children}</motion.div>
            </motion.div>
        </AnimatePresence>
    );
};

page.tsx

import { SectionTransition } from "./components/transition";

const ExternalLink: React.FC<ExternalLinkProps> = ({ href, icon, label }) => (
    <SectionTransition>
        <a
            href={href}
            <span>{icon}</span>
            <span>{label}</span>
        </a>
    </SectionTransition>
);

const socialLinks = [
    { href: "spoiler", icon: <spoiler />, label: "spoiler" },
    {
        href: "spoiler",
        icon: spoiler,
        label: spoiler,
    },
];

export default function Home() {
    return (
        <div className="grid gap-y-3 mt-6">
        {socialLinks.map(({ href, icon, label }) => (
            <ExternalLink
                key={href}
                href={href}
                icon={icon}
                label={label}
            />
        ))}
    </div>
)

When using SectionTransition to animate buttons one by one using staggerChildren, all buttons are animated simultaneously. I expect them to animate alternately.


Solution

  • you can use the custom prop in framer motion

    function Example() {
      return (
        <motion.div>
          {Array.from({ length: 4 }).map((_, i) => (
            <div className="bg-gray-400 overflow-hidden" key={i}>
              <motion.div custom={i} {...SlideAnimation}>
                element {i}
              </motion.div>
            </div>
          ))}
        </motion.div>
      );
    }
    const SlideAnimation= {
      initial: { y: "100%" },
      animate: (i) => ({
        y: "0",
        transition: { duration: 0.5, delay: 0.3 * i },
      }),
    };