Docs

Animated Follow Button

The Animated Follow Button is an interactive UI component with customizable entrance animations and dynamic text changes on click, offering flexible styling options. Perfect for engaging user interactions like follow or subscribe actions.

Installation

Install dependencies

npm install framer-motion

Run the following command

It will create a new file animated-follow-button.tsx inside the components/animata/button directory.

mkdir -p components/animata/button && touch components/animata/button/animated-follow-button.tsx

Paste the code

Open the newly created file and paste the following code:

"use client";
 
import React, { useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
 
interface AnimatedFollowButtonProps {
  initialText: React.ReactElement | string; // Text or element displayed initially
  changeText: React.ReactElement | string; // Text or element displayed after the button is clicked
  className?: string; // ClassName prop for custom button styling
  changeTextClassName?: string; // ClassName prop for custom styling of changeText
  animationType?:
    | "up-to-down"
    | "down-to-up"
    | "left-to-right"
    | "right-to-left"
    | "zoom-in"
    | "zoom-out"; // Prop to define animation type
}
 
const AnimatedFollowButton: React.FC<AnimatedFollowButtonProps> = ({
  initialText,
  changeText,
  className,
  changeTextClassName,
  animationType = "up-to-down", // Set default animation to "up-to-down"
}) => {
  const [isClicked, setIsClicked] = useState<boolean>(false); // Track button click state
 
  // Determine animation settings based on animationType prop
  const getAnimation = () => {
    switch (animationType) {
      case "down-to-up":
        return { initial: { y: 20 }, animate: { y: 0 }, exit: { y: 20 } }; // Down to up animation
      case "left-to-right":
        return { initial: { x: -20 }, animate: { x: 0 }, exit: { x: -20 } }; // Left to right animation
      case "right-to-left":
        return { initial: { x: 20 }, animate: { x: 0 }, exit: { x: 20 } }; // Right to left animation
      case "zoom-in":
        return { initial: { scale: 0.8 }, animate: { scale: 1 }, exit: { scale: 0.8 } }; // Zoom in animation
      case "zoom-out":
        return { initial: { scale: 1.2 }, animate: { scale: 1 }, exit: { scale: 1.2 } }; // Zoom out animation
      case "up-to-down":
      default:
        return { initial: { y: -20 }, animate: { y: 0 }, exit: { y: -20 } }; // Default: Up to down animation
    }
  };
 
  const animation = getAnimation(); // Get animation settings based on the selected type
 
  return (
    <AnimatePresence mode="wait">
      {isClicked ? (
        // Button after being clicked
        <motion.button
          className={`relative flex h-16 w-[200px] items-center justify-center overflow-hidden ${className}`} // Apply custom styling
          onClick={() => setIsClicked(false)} // On click, toggle button state
          initial={{ opacity: 0 }} // Initial animation for opacity
          animate={{ opacity: 1 }} // Animate to full opacity
          exit={{ opacity: 0 }} // Exit animation for opacity
        >
          {/* Change text with defined animation */}
          <motion.span
            key="clicked"
            className={`relative flex h-full w-full items-center justify-center font-semibold ${changeTextClassName}`} // Apply changeText className
            {...animation} // Apply selected animation
          >
            {changeText} {/* Display the changeText */}
          </motion.span>
        </motion.button>
      ) : (
        // Button before being clicked
        <motion.button
          className={`relative flex h-16 w-[200px] cursor-pointer items-center justify-center ${className}`} // Apply custom styling
          onClick={() => setIsClicked(true)} // On click, toggle button state
          initial={{ opacity: 0 }} // Initial animation for opacity
          animate={{ opacity: 1 }} // Animate to full opacity
          exit={{ opacity: 0 }} // Exit animation for opacity
        >
          {/* Initial text with defined animation */}
          <motion.span
            key="not-clicked"
            className="relative flex items-center justify-center font-semibold" // Flexbox for centering text
            {...animation} // Apply selected animation
          >
            {initialText} {/* Display the initialText */}
          </motion.span>
        </motion.button>
      )}
    </AnimatePresence>
  );
};
 
export default AnimatedFollowButton;

Credits

Built by Eshan Singh with Framer Motion.