Framer Motion Basics — Web Animation

Framer Motion Basics Framer Motion (sekarang diimpor dari motion/react) adalah library animasi untuk React yang menyediakan API deklaratif dan powerful. Dengan

Framer Motion Basics

Framer Motion (sekarang diimpor dari motion/react) adalah library animasi untuk React yang menyediakan API deklaratif dan powerful. Dengan Framer Motion, kamu bisa membuat animasi kompleks dengan kode yang sangat sedikit.

Instalasi & Import

npm install motion
import { motion, AnimatePresence } from 'motion/react';

animate Prop

Prop paling dasar — tentukan state akhir dan Framer Motion akan menganimasi ke sana:

// Fade in + slide up
<motion.div
  initial={{ opacity: 0, y: 20 }}
  animate={{ opacity: 1, y: 0 }}
>
  Hello World
</motion.div>

// Dengan konfigurasi transition
<motion.div
  initial={{ opacity: 0, scale: 0.8 }}
  animate={{ opacity: 1, scale: 1 }}
  transition={{ duration: 0.5, ease: 'easeOut' }}
>
  Animated Box
</motion.div>

Variants

Variants memungkinkan kamu mendefinisikan named animation states dan mengontrol animasi anak secara otomatis:

const containerVariants = {
  hidden: { opacity: 0 },
  visible: {
    opacity: 1,
    transition: {
      staggerChildren: 0.1, // delay antar anak
    },
  },
};

const itemVariants = {
  hidden: { opacity: 0, y: 20 },
  visible: { opacity: 1, y: 0 },
};

function List({ items }) {
  return (
    <motion.ul
      variants={containerVariants}
      initial="hidden"
      animate="visible"
    >
      {items.map((item) => (
        <motion.li key={item.id} variants={itemVariants}>
          {item.name}
        </motion.li>
      ))}
    </motion.ul>
  );
}

Gesture Animations

// whileHover — animasi saat di-hover
<motion.button
  whileHover={{ scale: 1.05 }}
  whileTap={{ scale: 0.95 }}
  transition={{ type: 'spring', stiffness: 400, damping: 17 }}
>
  Click Me
</motion.button>

// whileFocus
<motion.input
  whileFocus={{ scale: 1.02, borderColor: '#3b82f6' }}
/>

// whileDrag
<motion.div
  drag
  dragConstraints={{ left: 0, right: 300, top: 0, bottom: 300 }}
  whileDrag={{ scale: 1.1, cursor: 'grabbing' }}
>
  Drag me!
</motion.div>

AnimatePresence

Memungkinkan animasi exit saat komponen di-unmount dari DOM:

import { motion, AnimatePresence } from 'motion/react';

function Modal({ isOpen, onClose }) {
  return (
    <AnimatePresence>
      {isOpen && (
        <motion.div
          className="modal-overlay"
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          exit={{ opacity: 0 }}
          onClick={onClose}
        >
          <motion.div
            className="modal-content"
            initial={{ opacity: 0, scale: 0.9, y: 20 }}
            animate={{ opacity: 1, scale: 1, y: 0 }}
            exit={{ opacity: 0, scale: 0.9, y: 20 }}
            transition={{ type: 'spring', damping: 25 }}
            onClick={(e) => e.stopPropagation()}
          >
            <h2>Modal Content</h2>
            <button onClick={onClose}>Close</button>
          </motion.div>
        </motion.div>
      )}
    </AnimatePresence>
  );
}

Spring Transitions

Framer Motion menggunakan spring animation secara default:

// Default spring
<motion.div animate={{ x: 100 }} />

// Custom spring
<motion.div
  animate={{ x: 100 }}
  transition={{
    type: 'spring',
    stiffness: 300,  // kekakuan (default: 100)
    damping: 20,     // redaman (default: 10)
    mass: 1,         // massa (default: 1)
  }}
/>

// Tween (duration-based, bukan spring)
<motion.div
  animate={{ x: 100 }}
  transition={{
    type: 'tween',
    duration: 0.5,
    ease: 'easeInOut',
  }}
/>

Contoh: Animated Card List

function CardList({ cards }) {
  return (
    <div className="grid gap-4">
      {cards.map((card, index) => (
        <motion.div
          key={card.id}
          className="p-4 bg-white rounded-lg shadow"
          initial={{ opacity: 0, y: 20 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ delay: index * 0.1 }}
          whileHover={{
            y: -4,
            boxShadow: '0 10px 25px rgba(0,0,0,0.1)',
          }}
        >
          <h3>{card.title}</h3>
          <p>{card.description}</p>
        </motion.div>
      ))}
    </div>
  );
}

Framer Motion membuat animasi React jadi menyenangkan dan deklaratif. Di pelajaran berikutnya, kita akan belajar layout animation yang lebih advanced.