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.