Amaze the little ones by staggering children using framer-motion with a custom component as the child

Looking to implement a mobile menu with a cool fading effect on the navigation items, but something seems off. The NavLink items all appear simultaneously instead of staggered loading.

Initially, considered using 'delay' instead of 'delayChildren' but that didn't solve the issue.

Check out the mobileNav.tsx code below:

'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;

And here is the content of 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;

Answer №1

Using a custom component is not the issue here. You should consider removing the initial, animate, and exit props from your <NavLink /> component.

According to the Framer Motion Overview documentation, in the section on Propagation:

If a motion component contains children, any changes in variant will cascade down through the component hierarchy until a child component defines its own animate property.

By adding initial, animate, and exit to child motion elements, you will override any variant changes made by parent motion elements.

It's important to note that the advanced orchestration transitions (when, delayChildren, staggerChildren) are only available when using variants. You can learn more about orchestration here.

Check out this live example.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

When defining a class property in TypeScript, you can make it optional by not providing

Is there a way to make a property on a Class optional without it being undefined? In the following example, note that the Class constructor takes a type of itself (this is intentional) class Test { foo: number; bar: string; baz?: string; construc ...

Initiate a request between two containers using an API call

I am currently running a node application, a front-end app using Next.js, and utilizing Redis and Postgres as databases. I have containerized Next.js and Node.js separately with Docker. version: '3' services: redis-server: image: 'redi ...

Encountering difficulties in loading my personal components within angular2 framework

I encountered an issue while trying to load the component located at 'app/shared/lookup/lookup.component.ts' from 'app/associate/abc.component.ts' Folder Structure https://i.stack.imgur.com/sZwvK.jpg Error Message https://i.stack.img ...

Encountering a hydration issue in Next.js when attempting to refresh the page after switching languages (excluding English) with next-translate/useTranslation

I've encountered an issue with the useTranslation hook from the next-translate package in my Next.js project. Although all languages are being recognized, I'm facing a hydration error whenever I change the language and refresh the page. Below is ...

The data type 'number' cannot be assigned to the data type 'undefined'. Error code: ts(2322)

I encountered an issue where it's giving me an error stating that type number cannot be assigned to type undefined on the last digit (1) in scale={[1.618, 1, 1]}. Can anyone help me figure out how to resolve this TypeScript error? "use client&quo ...

Converting an array of arguments into tuples within the range of <T extends Tuple> is denoted by [T, (...args: NonNullArray<T>) => any], where each tuple represents the argument of a

Let's start with a simple function that takes a tuple as its first argument and a function whose arguments are elements of the tuple that are not null as its second argument: let first: number | null | undefined; let last: number | null | undefined; l ...

Exploring unit tests: Customizing an NGRX selector generated by entityAdapter.getSelectors()

Let's imagine a scenario where our application includes a books page. We are utilizing the following technologies: Angular, NGRX, jest. To provide some context, here are a few lines of code: The interfaces for the state of the books page: export int ...

Receiving a null array from the web3.eth.getAccounts() function

While working with next.js, I encountered an issue where web3.eth.getAccounts() was returning an empty array on the server side. Here are two of my files - index.js and web3.js. index.js: import React, { Component } from "react"; import web3 from "../eth ...

What might be the underlying reason for Chrome displaying a net::ERR_FAILED error when attempting to make a request from a Vue frontend to a C# API using Axios?

I have a C# Backend+API that I interact with from my Vue Application using axios to make requests. In the C# code, there is an endpoint that looks like this: // GET: api/Timezone public HttpResponseMessage GetTimezoneData() { ...

Detecting When a User Reaches the Bottom of the Screen in REACTjs

My goal is to monitor when the user reaches the bottom of the screen and then trigger a function to load more data. Within my app.js file, I have a Products component that handles the data fetching. The Products component is enclosed in a div with a class ...

What is the best way to create a dynamic URL linking to an external site in Angular 5?

When attempting to create a link like this: <a [href]="getUrl()">click me</a> getUrl() { return this.domSanitizer.bypassSecurityTrustUrl('http://sampleUrl.com'); } The link is not clickable. When hovering over the ...

What is the best way to integrate Nextjs Link Component with framer motion in a Typescript environment?

Description I am trying to use Framer Motion to animate a Next.js Link component in a TypeScript environment, but I keep encountering a type error: Property 'Link' does not exist on type '(<Props extends {}>(Component: string | Compo ...

What is the best way to set up a session in a Next.js project?

I am currently utilizing Next js for my project development. I've successfully crafted a unique signup form within the platform where users can input their email and password, followed by an OTP being sent to their email address for verification purpo ...

Angular2: Error - trying to access 'this.' which is not defined

I have a function that is designed to retrieve and display the "best player" from an array of objects, which essentially refers to the player with the most likes. The functionality of this function works as intended and displays the desired output. However ...

Mastering Light and Camera Selection in Three.js

Question, In the editor found at this link, you can click on a light or camera to select it. I am familiar with using raycaster.intersectObjects(objects) to select meshes, but how can I achieve the same result for lights and cameras which do not have mesh ...

Using TypeScript to implement functions with multiple optional parameters

Imagine having a function like the one shown here: function addressCombo(street1:string, street2:string = "NA", street3?:string) { console.log("street1: " + street1); console.log("street1: " + street2); console.log("street2: " + street3); } I ...

Issue with Angular custom tag displaying and running a function

I have created a custom HTML tag. In my next.component.ts file, I defined the following: @Component({ selector: 'nextbutton', template: ` <button (click) = "nextfunc()">Next</button> ` }) export class NextComponent{ nextfunc( ...

Tips for using jest.mock with simple-git/promise

I have been attempting to simulate the checkout function of simple-git/promise in my testing but without success. Here is my current approach: jest.mock('simple-git/promise', () => { return { checkout: async () => { ...

Here is an example showcasing how to use Angular 2 to make an

How can I correctly retrieve json data from an http get request in Angular 2? Currently, I am working on testing some local data with a mocked endpoint. Although I am able to see the result in the http.get() method, I am facing issues when trying to assign ...

"Encountering an issue with the Foreach function in nextjs when iterating through

I attempted to iterate through each character in a String, but the SPANS are not displaying. What could I be doing incorrectly? export default function Work() { const logoText = "The future starts here."; return ( <div className=& ...