Creating an Animated Sign Up Button
In this article, I'm rebuilding the animated sign-up button I've encountered in Emil Kowalski's Animations on the Web course.
The first time I saw this animation, I truly felt inspired.
The animation sticks to the button itself, not affecting the layout of the page. It's a great example of how animations can enhance user experience without being intrusive.
Now let's dive into building this button.
Button Structure
Our animation is built with React and Framer Motion Motion, a library that makes it easy to create animations in Web applications, especially with React.
The button has three different states, which are reflected by the changing content of the button: idle
, loading
and success
So, our basic structure without any animations would look like this:
type ButtonState = "idle" | "loading" | "success";
export const AnimatedSignUpButton = () => {
const [buttonState, setButtonState] = useState<ButtonState>("idle");
const buttonStates: {
[key in ButtonState]: string | JSX.Element;
} = {
idle: "Sign up for newsletter",
loading: (
<div className="size-4 animate-spin">
<Loader2 className={styles.icon} />
</div>
),
success: "Thank you!",
}
return (
<button>
{buttonStates[buttonState]}
</button>
);
}
Handle state changes
In order to change the content of the button, we add a click listener and a handleSubmit
function.
This function changes the state from idle
to loading
and then to success
after a short delay.
const handleSubmit = () => {
if (buttonState !== "idle") {
return;
}
setButtonState("loading");
setTimeout(() => {
setButtonState("success");
}, 2000);
setTimeout(() => {
setButtonState("idle");
}, 4000);
};
return (
<button onClick={handleSubmit}>
{buttonStates[buttonState]}
</button>
);
Adding Animations
Next, we need to import the motion
object from framer-motion
.
Inside our button, we wrap the content in a motion.span
component. This tells Motion that we want to animate this element.
We can then add animations to the button by setting the initial
, animate
, exit
and transition
properties. In our case, we want the elements to slide in from the top and slide out to the bottom.
To ensure that Motion triggers the animation when the button state changes, we need to add a key
property to the motion.span
component. This property should be unique for each state.
<button className={styles.button} onClick={handleSubmit}>
<AnimatePresence mode="popLayout" initial={false}>
<motion.span
className={styles.span}
key={buttonState}
transition={{
type: "spring",
duration,
bounce,
}}
initial={{
opacity: 0,
y: -25,
}}
animate={{
opacity: 1,
y: 0,
}}
exit={{
opacity: 0,
y: 25,
}}
>
{buttonStates[buttonState]}
</motion.span>
</AnimatePresence>
</button>
And that's it! We've created a beautiful animated sign-up button 🎉
Playground
Here you can play around with the button and see how it behaves in different states. Drag the Duration and Bounce sliders to see how the animation changes.