DEV Community

Jay Sarvaiya
Jay Sarvaiya

Posted on

Build Your Own Animated Component Library with React + Framer Motion

Why Build a Component Library?

  • Reuse animations without rewriting code
  • Keep your UI consistent across projects
  • Make it easy for teammates (or your future self)
  • Learn how to structure scalable React components

Step 1: Setup

Install React + Framer Motion:

npm install framer-motion
Enter fullscreen mode Exit fullscreen mode

Create a folder structure like this:

animated-components/
│
├── src/
│   ├── components/
│   │   ├── AnimatedButton.jsx
│   │   ├── AnimatedCard.jsx
│   │   ├── AnimatedModal.jsx
│   │
│   └── index.js
│
├── example/   # Demo playground
│   ├── App.jsx
│   └── index.js
│
├── package.json
├── README.md
└── vite.config.js (or Next.js if you prefer)
Enter fullscreen mode Exit fullscreen mode

Step 2: Create an Animated Button

// components/AnimatedButton.jsx
import { motion } from "framer-motion";

export default function AnimatedButton({ children, onClick }) {
  return (
    <motion.button
      whileHover={{ scale: 1.1 }}
      whileTap={{ scale: 0.95 }}
      className="px-4 py-2 bg-indigo-500 text-white rounded-lg shadow"
      onClick={onClick}
    >
      {children}
    </motion.button>
  );
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Create an Animated Card

// components/AnimatedCard.jsx
import { motion } from "framer-motion";

export default function AnimatedCard({ children }) {
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.5, ease: "easeOut" }}
      className="p-6 bg-white rounded-xl shadow-md"
    >
      {children}
    </motion.div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Create an Animated Modal

// components/AnimatedModal.jsx
import { motion, AnimatePresence } from "framer-motion";

export default function AnimatedModal({ isOpen, onClose, children }) {
  return (
    <AnimatePresence>
      {isOpen && (
        <motion.div
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          exit={{ opacity: 0 }}
          className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50"
          onClick={onClose}
        >
          <motion.div
            initial={{ scale: 0.8, opacity: 0 }}
            animate={{ scale: 1, opacity: 1 }}
            exit={{ scale: 0.8, opacity: 0 }}
            transition={{ duration: 0.3 }}
            className="bg-white p-6 rounded-xl shadow-lg"
            onClick={(e) => e.stopPropagation()}
          >
            {children}
          </motion.div>
        </motion.div>
      )}
    </AnimatePresence>
  );
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Export from index.js

// index.js
export { default as AnimatedButton } from "./components/AnimatedButton";
export { default as AnimatedCard } from "./components/AnimatedCard";
export { default as AnimatedModal } from "./components/AnimatedModal";
Enter fullscreen mode Exit fullscreen mode

Now you have a mini animated component library ready to import anywhere:

import { AnimatedButton, AnimatedCard, AnimatedModal } from "./components";
Enter fullscreen mode Exit fullscreen mode

Step 6: Demo App (example/)

This is where users can see your components in action.

// example/App.jsx
import { useState } from "react";
import { AnimatedButton, AnimatedCard, AnimatedModal } from "../src";

export default function App() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <div className="p-8 space-y-6">
      <AnimatedCard>
        <h2 className="text-xl font-bold">Hello from Animated Card 🎉</h2>
      </AnimatedCard>

      <AnimatedButton onClick={() => setIsOpen(true)}>
        Open Modal
      </AnimatedButton>

      <AnimatedModal isOpen={isOpen} onClose={() => setIsOpen(false)}>
        <h2 className="text-lg font-bold">I am an Animated Modal 🚀</h2>
      </AnimatedModal>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Step 7: Docs + GitHub

  • Create a README.md with installation + usage instructions.
  • Push to GitHub.
  • Add a demo site using Vite or Next.js + GitHub Pages / Vercel.

Step 8: Publish to npm

You can even publish this as an npm package so others can install it:

npm login
npm publish --access public
Enter fullscreen mode Exit fullscreen mode

Then developers can do:

npm install animated-components-lib
Enter fullscreen mode Exit fullscreen mode

And use it like:

import { AnimatedButton } from "animated-components-lib";
Enter fullscreen mode Exit fullscreen mode

Top comments (0)