Thank you for singing up for the waitlist. This demo page contains two sections from the "How do I code animations" lesson. These are some small
Exit animations in React are hard. AnimatePresence
in Framer Motion allows components to animate out when they're removed from the React tree. It has good DX as well. All you need to do is wrap an element you want to animate out with AnimatePresence, and add the exit prop. That's it.
AnimatePresence
is also the key for this button animation, which is used on the login page of this course
Let's try and recreate it!
"use client"; import { useState } from "react"; import { AnimatePresence, motion } from "framer-motion"; import { Spinner } from "./Spinner"; const buttonCopy = { idle: "Send me a login link", loading: <Spinner size={16} color="rgba(255, 255, 255, 0.65)" />, success: "Login link sent!", }; export default function SmoothButton() { const [buttonState, setButtonState] = useState("idle"); return ( <div className="outer-wrapper"> <button className="blue-button" disabled={buttonState === "loading"} onClick={() => { if (buttonState === "success") return; setButtonState("loading"); setTimeout(() => { setButtonState("success"); }, 1750); setTimeout(() => { setButtonState("idle"); }, 3500); }} > <AnimatePresence mode="popLayout" initial={false}> <motion.span transition={{ type: "spring", duration: 0.3, bounce: 0 }} initial={{ opacity: 0, y: -25 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: 25 }} key={buttonState} > {buttonCopy[buttonState]} </motion.span> </AnimatePresence> </button> </div> ); }
We can also make a reusable component out of this, so that it doesn't have to be used only for this button. Here, I also used variants. Variants are predefined sets of targets which can be then used in the animate prop. They can be useful if you find yourself repeating the same animation multiple times. In this case, I knew that enter and exit animation would be the same, so I used it, but there are definitely better use cases for it.
Framer Motion allows us to animate height from a fixed value to auto
. This is something that's not possible with CSS animations. The problem we are having here is that we want to animate from auto
to auto
, which Framer Motion doesn't support. But often times we need to animate dynamic heights, like the Family drawer below. We will build the full version of the drawer in the walkthroughs in the course btw!
So, how are we supposed to handle dynamic heights? Below is a simple example where clicking the button changes the content, which results in height change. Try to animate the height automatically when the content changes.
This one is not easy, it might be tricky, and perhaps frustrating. However, struggling and failing is much more productive than reading through the solution. When I started to learn how to code I didn't want to struggle and I regret it. There is a small hint in the code below though!
import { motion } from "framer-motion"; import { useState, useRef, useEffect } from "react"; import useMeasure from 'react-use-measure' export default function Example() { const [showExtraContent, setShowExtraContent] = useState(false); return ( <div className="wrapper"> <button className="button" onClick={() => setShowExtraContent((b) => !b)}> Toggle height </button> <div className="element"> <div className="inner"> <h1>Fake Family Drawer</h1> <p> This is a fake family drawer. Animating height is tricky, but satisfying when it works. </p> {showExtraContent ? ( <p>This extra content will change the height of the drawer. Some even more content to make the drawer taller and taller and taller...</p> ) : null} </div> </div> </div> ); }