I am creating a login signup page in ReactJS using Framer Motion. I have created 2 components login and signup each having buttons, clicking on which the other component will render. I have used AnimatePresence to do exit and entry animation. but the exit animation is not working, in the exit part the component gets removed suddenly from the DOM tree without doing animation.
The component structure is like this:
- UserLoginSignUp.jsx (Parent component)
- Login. jsx** (children component)
- SignUp.jsx** (children component)
UserLoginSignUp.jsx
import { Login } from "./Login";
import { Signup } from "./Signup";
import { AnimatePresence } from "framer-motion";
function UserLoginSignUp({ isloged, setisloged }) {
return (
<>
<div>
<div className="w-[40vw]">
<AnimatePresence>
{isloged ? (
<Login setisloged={setisloged} />
) : (
<Signup setisloged={setisloged} />
)}
</AnimatePresence>
</div>
<div></div>
</div>
</>
);
}
export { UserLoginSignUp };
Login.jsx
import { useState } from "react";
import { motion } from "framer-motion";
function Login({ setisloged }) {
const [masterKey, setMasterKey] = useState("");
const handleLogin = () => {
};
const signupHandler = () => {
setisloged(false);
};
return (
<motion.div
key="login"
initial={{ opacity: 0, y: -100 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 1 }}
exit={{ opacity: 0, y: 200 }}
className="min-h-screen flex items-center justify-center bg-gradient-to-b from-[#95dab6] to-[#83b2d0]"
>
<motion.div
initial={{ opacity: 0, y: -100 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 1 }}
exit={{ opacity: 0, y: 200 }}
className="bg-white p-8 rounded shadow-md w-96"
>
<h2 className="text-2xl font-semibold mb-4">Login</h2>
<div className="mb-4">
<input
type="text"
placeholder="Enter master key"
className="w-full px-3 py-2 border rounded focus:outline-none focus:ring-2 focus:ring-red-600 focus:border-blue-300"
value={masterKey}
onChange={(e) => setMasterKey(e.target.value)}
/>
</div>
<button
className="w-full bg-[#95dab6] text-white py-2 rounded hover:bg-green-400"
onClick={handleLogin}
>
Login
</button>
<p className="mt-4 text-center">
Don't have an account?{" "}
<span
className="text-green-400 cursor-pointer"
onClick={signupHandler}
>
Signup
</span>
</p>
</motion.div>
</motion.div>
);
}
export { Login };
SignUp.jsx
import { useState } from "react";
import { motion } from "framer-motion";
function Signup({ setisloged }) {
const [fullName, setFullName] = useState("");
const [email, setEmail] = useState("");
const [masterKey, setMasterKey] = useState("");
const handleSignup = () => {
};
const loginHandler = () => {
setisloged(true);
};
return (
<motion.div
key="signup"
initial={{ opacity: 0, y: -100 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 1 }}
exit={{ opacity: 0, y: 200 }}
className="min-h-screen flex items-center justify-center bg-gradient-to-b from-blue-600 to-purple-400">
<motion.div
initial={{ opacity: 0, y: -100 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 1 }}
exit={{ opacity: 0, y: 200 }}
className="bg-white p-8 rounded shadow-md w-96"
>
<h2 className="text-2xl font-semibold mb-4">Signup</h2>
<div className="mb-4">
<input
type="text"
placeholder="Enter Full Name"
className="w-full px-3 py-2 border rounded focus:outline-none focus:ring focus:border-blue-300"
value={fullName}
onChange={(e) => setFullName(e.target.value)}
/>
</div>
<div className="mb-4">
<input
type="email"
placeholder="Enter Email"
className="w-full px-3 py-2 border rounded focus:outline-none focus:ring focus:border-blue-300"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div className="mb-4">
<input
type="text"
placeholder="Enter your Masterkey"
className="w-full px-3 py-2 border rounded focus:outline-none focus:ring focus:border-blue-300"
value={masterKey}
onChange={(e) => setMasterKey(e.target.value)}
/>
</div>
<button
className="w-full bg-blue-500 text-white py-2 rounded hover:bg-blue-600 mb-2"
onClick={handleSignup}
>
Signup
</button>
<button
className="w-full bg-gray-300 text-gray-700 py-2 rounded hover:bg-gray-400"
onClick={loginHandler}
>
Login
</button>
</motion.div>
</motion.div>
);
}
export { Signup };
AnimatePresence has a
mode
prop which issync
by default. changing it towait
orpopLayout
may fix your issue