Panduan Lengkap Motion (Formerly Framer Motion) untuk Pemula: Membuat Animasi React dengan Vite di 2025

Pernah gak sih kamu buka website atau aplikasi web yang animasinya smooth banget? Rasanya pengalaman browsing jadi lebih menyenangkan kan? Nah, animasi dalam web development itu bukan cuma soal estetika doang loh. Animasi yang tepat bisa banget meningkatkan user experiance secara signifikan.

Bayangin aja, ketika user klik tombol terus ada feedback visual yang halus, atau saat transisi antar halaman yang smooth, semua itu bikin aplikasi kamu terasa lebih responsif dan profesional. Di tahun 2025 ini, standar untuk web experience udah makin tinggi. User sekarang udah terbiasa dengan aplikasi mobile yang animasinya mulus, jadi mereka expect hal yang sama dari aplikasi web.

Animasi yang bagus bisa banget membantu user memahami flow aplikasi kamu, memberikan feedback yang jelas, dan tentunya bikin mereka betah lebih lama. Bahkan studi menunjukkan kalau animasi yang tepat bisa meningkatkan conversion rate dan engagement user secara drastis.

Kenapa Motion?

Kalau kita bicara soal library animasi untuk React, Motion (yang sebelumnya dikenal sebagai Framer Motion) adalah salah satu pilihan terbaik yang ada saat ini. Kenapa? Karena Motion itu punya API yang super intuitif dan mudah dipahami, bahkan buat pemula sekalipun.

Kamu gak perlu jadi expert di CSS animation atau JavaScript timing functions yang rumit. Dengan Motion, kamu tinggal deklarasikan gimana komponen kamu harus beranimasi, dan library-nya yang bakal handle semua kompleksitasnya. Plus, Motion juga production-ready dan udah dipake sama ribuan aplikasi besar di luar sana.

Yang bikin Motion makin powerful adalah performa-nya yang excellent. Library ini menggunakan hardware acceleration dan optimasi yang canggih, jadi animasi kamu bakal tetep smooth bahkan di device yang spesifikasinya lebih rendah. Motion juga punya fitur-fitur advance kayak gesture animations, scroll-triggered animations, sama layout animations yang bikin tranformasi layout jadi mulus banget. Semua fitur ini dikemas dalam bundle size yang relatif kecil, jadi gak bikin aplikasi kamu jadi berat.

Kenapa Vite?

Terus kenapa kita pake Vite sebagai build tool-nya? Simple, karena Vite adalah next-generation frontend tooling yang bikin development experience jadi jauh lebih enjoyable.

Pertama, Vite punya instant server start. Berbeda sama webpack atau create-react-app yang kadang butuh waktu lama buat startup, Vite bisa langsung jalan dalam hitungan detik, bahkan untuk project yang besar sekalipun. Ini karena Vite menggunakan native ES modules di browser waktu development, jadi dia gak perlu bundle semua code kamu dulu sebelum serve.

Kedua, fast refresh di Vite juga luar biasa cepat. Setiap kali kamu save perubahan di code, update-nya langsung keliatan di browser hampir instantly. Ini beda banget sama hot module replacement tradisional yang kadang butuh beberapa detik. Dengan Vite, feedback loop kamu jadi super cepat, dan ini bikin proses development jadi lebih produktif. Kamu bisa eksperimen dengan animasi, tweak parameter, dan langsung lihat hasilnya tanpa harus nunggu lama.

Ketiga, Vite punya modern tooling yang udah pre-configured dengan baik. Support untuk TypeScript, JSX, CSS modules, dan berbagai fitur modern lainnya udah built-in. Buat production build, Vite pake Rollup di belakang layar yang menghasilkan bundle yang super optimized. Kombinasi antara developer experience yang excellent dan production performance yang optimal bikin Vite jadi pilihan yang sempurna buat project kita kali ini.

Apa yang Akan Kita Pelajari?

Jadi dalam tutorial ini, kita bakal belajar gimana caranya bikin animasi React yang keren menggunakan Motion dan Vite. Kita bakal mulai dari setup project, konsep dasar Motion, sampe implementasi berbagai jenis animasi yang bisa langsung kamu pake di project BuildWithAngga atau project pribadi kamu.

Siap buat bikin aplikasi web yang lebih hidup dan engaging? Yuk kita mulai!

Apa itu Motion?

Motion — JavaScript & React animation library
Motion — JavaScript & React animation library

Motion adalah library animasi yang powerful dan fleksibel buat bikin animasi di aplikasi web kamu. Kalau kamu pernah denger Framer Motion sebelumnya, yap betul banget, ini adalah evolusi terbaru dari library tersebut. Motion dirancang dengan filosofi yang sederhana: bikin animasi harusnya semudah menulis kode biasa, tanpa harus pusing mikirin timing functions yang ribet atau CSS keyframes yang kompleks.

Library ini pertama kali muncul sebagai bagian dari ekosistem Framer, sebuah design tool yang populer di kalangan designer dan developer. Awalnya bernama Framer Motion dan diluncurkan sekitar tahun 2019, library ini langsung mendapat perhatian besar dari komunitas React karena pendekatannya yang inovatif dalam menangani animasi. Para developer langsung jatuh cinta sama API-nya yang declarative dan mudah dipahami, bahkan buat yang baru pertama kali nyoba bikin animasi.

Perubahan Besar: Dari Framer Motion ke Motion

Nah, ini yang penting banget buat kamu tau. Di bulan November 2024, terjadi perubahan signifikan dalam ekosistem library ini. Framer Motion secara resmi berganti nama menjadi Motion dan sekarang beroperasi sebagai project yang independen dari Framer. Keputusan ini diambil karena library-nya udah berkembang jauh melampaui cakupan awal sebagai tool animasi khusus React aja.

Rebranding ini bukan cuma soal ganti nama doang loh. Motion sekarang punya website baru di motion.dev yang lebih fokus sama dokumentasi dan pengembangan berbasis komunitas. Tim di balik Motion juga mengumumkan kalau mereka mau memperluas dukungan ke berbagai framework dan bahkan vanilla JavaScript, jadi gak terbatas di React aja. Ini langkah besar yang bikin Motion jadi lebih mudah diakses buat developer dengan berbagai latar belakang.

Yang perlu kamu perhatikan adalah kalau kamu liat tutorial atau artikel lama yang masih nyebut "Framer Motion", jangan bingung. Konsep dan cara pakainya masih sama, cuma namanya aja yang berubah. Nama package di npm juga bakal migrasi secara bertahap, tapi untuk kompatibilitas mundur, nama lama masih bisa dipake. Jadi project lama kamu gak bakal langsung rusak.

Setup Project dengan Vite + React + Motion

Oke, sekarang saatnya kita mulai kotor tangan dan setup project kita. Di bagian ini, kita bakal setup project dari awal sampe siap dipake buat bikin animasi keren. Jangan khawatir, prosesnya mudah dipahami kok dan gak bakal lama.

Requirement yang Harus Kamu Punya

Sebelum mulai, mari kita pastiin dulu semua peralatan tempur kita udah siap. Gak perlu banyak kok, cuma tiga hal essensial ini:

Node.js versi 18 ke atas

Node.js — Run JavaScript Everywhere
Node.js — Run JavaScript Everywhere

Ini adalah fondasi utama yang harus ada. Kenapa harus versi 18? Karena Vite butuh fitur-fitur modern dari Node.js buat bisa jalan dengan optimal dan cepet. Kalau kamu belum install atau masih pake versi lama, langsung aja download dari nodejs.org dan install versi LTS terbaru. Buat ngecek versi Node.js yang udah terinstall, tinggal jalankan node --version di terminal kamu.

Package Manager (npm, yarn, atau pnpm)

Package manager ini ibarat toko aplikasi buat JavaScript. Kamu bakal pake ini buat download dan manage semua library yang dibutuhkan. Kabar baiknya, npm udah otomatis bundled sama Node.js, jadi kamu gak perlu install apapun lagi. Di tutorial ini kita bakal pake npm karena paling universal dan pasti udah ada di komputer kamu.

Kalau kamu prefer package manager lain kayak yarn atau pnpm karena lebih cepet atau udah terbiasa, totally fine! Tinggal ganti command-nya aja nanti. Misalnya npm install jadi yarn add atau pnpm add. Konsepnya persis sama.

Code Editor (VS Code sangat direkomendasikan)

Visual Studio Code - Code Editing. Redefined
Visual Studio Code - Code Editing. Redefined

Kamu butuh editor yang nyaman buat nulis code. Saya sangat rekomendasikan VS Code karena gratiss, ringan, dan punya ekosistem extension yang luar biasa lengkap. Beberapa extension wajib yang bikin hidup kamu lebih mudah:

  • ES7+ React/Redux/React-Native snippets (buat shortcut coding)
  • Prettier (auto-format code biar rapi)
  • ESLint (deteksi error sebelum jalan)
  • Auto Rename Tag (edit opening tag, closing tag ikut berubah)

Tapi kalau kamu udah invest waktu dan nyaman sama editor lain kayak WebStorm, Sublime Text, atau bahkan Vim, gak ada masalah sama sekali. Yang penting kamu produktif dan enjoy pake editor itu.

Langkah-Langkah Instalasi

A. Membuat Project Vite

Langkah pertama adalah bikin project Vite baru. Buka terminal atau command prompt kamu, terus jalankan perintah ini:

npm create vite@latest bwa-motion-app

Setelah kamu jalankan perintah itu, Vite bakal nanya beberapa pertanyaan. Pertama, pilih framework-nya: pilih React. Kedua, pilih variant-nya: pilih JavaScript atau TypeScript sesuai preferensi. Buat tutorial ini, kita bakal pake JavaScript biasa biar lebih simple buat pemula. Tapi kalau kamu udah nyaman sama TypeScript, silahkan pilih TypeScript.

Proses ini cepet banget, literally cuma beberapa detik. Ini salah satu keunggulan Vite dibanding create-react-app yang biasanya butuh waktu lebih lama. Setelah selesai, masuk ke folder project yang baru dibuat:

cd bwa-motion-app

B. Menginstall Motion

Setelah dependencies dasar terinstall, sekarang waktunya install Motion. Ini super gampang, cukup jalankan:

npm install motion

Perintah ini bakal download dan install Motion library beserta semua dependencies-nya. Prosesnya cepet karena Motion punya ukuran bundle yang relatif kecil. Setelah selesai, kamu bisa cek di file package.json, harusnya ada motion di bagian dependencies.

Perlu dicatat, kalau kamu masih nemuin tutorial lama yang pake npm install framer-motion, itu versi lama. Sekarang nama package-nya udah berubah jadi motion aja. Tapi tenang, kalau kamu gak sengaja install framer-motion, fungsionalitasnya masih sama kok, cuma nanti lebih baik migrasi ke package baru buat dapet update terbaru.

C. Struktur Project

Setelah setup selesai, mari kita lihat struktur folder project kita. Ini penting buat kamu paham dimana naruh file-file nantinya:

bwa-motion-app/
├── public/
├── src/
│   ├── App.jsx
│   ├── main.jsx
│   └── index.css
├── index.html
├── package.json
└── vite.config.js

Folder public adalah tempat kamu naruh asset static kayak gambar atau file lain yang gak perlu diproses sama build tool. Folder src adalah tempat semua code kamu berada. File App.jsx adalah komponen utama aplikasi kita, main.jsx adalah entry point, dan index.css buat styling global.

File index.html di root adalah template HTML utama. Beda sama create-react-app yang naruh index.html di folder public, Vite naruhnya di root. File vite.config.js adalah tempat konfigurasi Vite, tapi buat kebanyakan kasus, konfigurasi bawaan udah cukup bagus.

D. Menjalankan Development Server

Sekarang mari kita coba jalankan development server. Dari terminal, jalankan perintah:

npm run dev

Tampilan Awal Vite
Tampilan Awal Vite

Boom! Server langsung nyala. Kamu bakal lihat pesan di terminal yang ngasih tau server jalan di http://localhost:5173. Buka URL itu di browser, dan kamu harusnya lihat halaman welcome dari Vite + React. Cepet kan? Ini yang bikin developer jatuh cinta sama Vite.

Coba ubah text di file App.jsx, save, dan lihat browser kamu. Perubahan langsung keliatan tanpa perlu refresh manual. Ini namanya Hot Module Replacement (HMR), dan di Vite kecepatannya luar biasa. Bahkan di project besar dengan ratusan komponen, HMR tetep cepat.

Konfigurasi Vite untuk Motion

Kabar baiknya, kamu gak perlu konfigurasi spesial buat pake Motion dengan Vite. Motion udah sepenuhnya kompatibel dengan Vite langsung dari kotak. Tapi ada beberapa optimasi opsional yang bisa kamu lakukan kalau mau.

Buka file vite.config.js. Secara bawaan, filenya kurang lebih kayak gini:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
})

Konfigurasi ini udah cukup buat kebanyakan kasus. Tapi kalau kamu mau optimasi ukuran build, kamu bisa tambah beberapa opsi:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          motion: ['motion']
        }
      }
    }
  }
})

Konfigurasi ini bakal pisahin Motion ke chunk terpisah waktu build, jadi kalau ada update di code kamu tapi Motion gak berubah, pengguna gak perlu download ulang Motion. Tapi buat project kecil atau medium, optimasi ini opsional aja.

Tips Tambahan

Kalau kamu menemui error atau masalah waktu setup, beberapa hal yang bisa dicek: pastikan Node.js versi kamu minimal 18, coba delete folder node_modules dan file package-lock.json terus install ulang, atau pastikan gak ada salah ketik di perintah yang kamu jalankan.

Satu lagi, kalau kamu kerja di tim atau mau share project ini, pastikan file .gitignore udah include node_modules dan dist. Vite udah otomatis bikin .gitignore yang tepat, tapi gak ada salahnya cek lagi.

Sekarang setup kita udah selesai! Di chapter selanjutnya, kita bakal mulai belajar konsep-konsep dasar Motion dan bikin animasi pertama kita yang lebih kompleks.

Konsep Dasar Motion

Sekarang kita masuk ke bagian yang paling seru: belajar konsep dasar Motion. Di chapter ini, kita bakal pahami gimana Motion bekerja dan mulai bikin animasi pertama kita. Gak usah khawatir, konsepnya sangat intuitif dan mudah dipahami, bahkan buat yang baru pertama kali belajar animasi.

Component Motion: Transformasi HTML Element

Konsep utama Motion adalah component motion. Ini adalah cara Motion mentransformasi HTML element biasa jadi element yang bisa dianimasikan. Gimana caranya? Sangat simpel. Kamu tinggal tambah prefix motion. di depan HTML tag apapun yang mau kamu animasikan.

Misalnya, kalau kamu punya <div> biasa, kamu ubah jadi <motion.div>. Kalau kamu punya <button>, jadi <motion.button>. Semua HTML element bisa ditransformasi dengan cara ini: <motion.h1>, <motion.p>, <motion.img>, dan seterusnya. Konsepnya mirip kayak styled-components kalau kamu pernah pake.

Yang menarik adalah component motion ini tetep berperilaku seperti HTML element biasa. Kamu tetep bisa pake className, style, onClick, dan semua props HTML standar. Bedanya, sekarang element kamu punya superpower: kemampuan untuk dianimasikan dengan mudah. Mari kita lihat contoh paling dasar:

import { motion } from 'motion/react'

function WelcomeCard() {
  return (
    <motion.div className="card">
      <h2>Selamat Datang di BuildWithAngga</h2>
      <p>Belajar Motion dari nol sampai mahir</p>
    </motion.div>
  )
}

export default WelcomeCard

Dengan code di atas, kamu udah punya component yang siap dianimasikan. Memang belum ada animasinya karena kita belum kasih instruksi animasi. Tapi fondasi nya udah ada. Sekarang mari kita kasih animasi ke component ini.

Props Fundamental Motion

Motion punya tiga props fundamental yang jadi pondasi semua animasi: initial, animate, dan transition. Memahami ketiga props ini adalah kunci untuk menguasai Motion. Mari kita bahas satu per satu dengan detail.

Props initial: Menentukan State Awal

Props initial adalah tempat kamu mendefinisikan kondisi awal element sebelum animasi dimulai. Ini adalah starting point animasi kamu. Kamu bisa set berbagai property CSS kayak opacity, position, scale, rotation, dan banyak lagi. Mari lihat contohnya:

import { motion } from 'motion/react'

function FadeInCard() {
  return (
    <motion.div
      initial={{ opacity: 0, y: 50 }}
      className="card"
    >
      <h2>Card dengan Fade In</h2>
      <p>Card ini muncul dari bawah dengan efek fade</p>
    </motion.div>
  )
}

export default FadeInCard

Di contoh ini, kita set opacity: 0 yang berarti element awalnya transparan (gak keliatan), dan y: 50 yang berarti element posisinya 50 pixel lebih bawah dari posisi normalnya. Properti y ini adalah shorthand untuk translateY di CSS transform. Motion juga punya x untuk horizontal, scale untuk ukuran, dan rotate untuk putaran.

Yang perlu kamu ingat, nilai di initial ini gak akan langsung keliatan kalau kamu gak kasih props animate juga. Element bakal stuck di state initial sampai ada instruksi untuk bergerak ke state selanjutnya.

Props animate: State Target yang Dituju

Props animate adalah destinasi akhir animasi kamu. Ini adalah kondisi dimana animasi akan berakhir. Motion secara otomatis bakal menghitung nilai-nilai intermediate antara initial dan animate, jadi kamu gak perlu mikirin manual. Ini yang bikin Motion sangat powerful dan mudah dipake.

Mari kita lengkapin contoh sebelumnya dengan menambahkan animate:

import { motion } from 'motion/react'

function FadeInCard() {
  return (
    <motion.div
      initial={{ opacity: 0, y: 50 }}
      animate={{ opacity: 1, y: 0 }}
      className="card"
    >
      <h2>Card dengan Fade In</h2>
      <p>Card ini muncul dari bawah dengan efek fade</p>
    </motion.div>
  )
}

export default FadeInCard

FadeIn Animation
FadeIn Animation

Sekarang animasi kita lengkap! Element akan mulai dengan opacity 0 dan posisi 50 pixel di bawah, lalu secara otomatis beranimasi menuju opacity 1 (fully visible) dan posisi normal (y: 0). Motion bakal smoothly interpolate semua nilai diantaranya. Hasil akhirnya adalah efek fade in dari bawah yang smooth dan profesional.

Kamu bisa animasikan banyak property sekaligus. Misalnya, kombinasi fade, slide, dan scale:

<motion.div
  initial={{ opacity: 0, y: 30, scale: 0.9 }}
  animate={{ opacity: 1, y: 0, scale: 1 }}
  className="feature-card"
>
  <h3>Fitur Unggulan BuildWithAngga</h3>
  <p>Kursus berkualitas dengan mentor berpengalaman</p>
</motion.div>

FadeIn Animation
FadeIn Animation

Animasi ini bakal bikin element fade in sambil naik dari bawah dan sedikit membesar. Kombinasi ini sering dipake di landing page modern karena terlihat dynamic dan engaging.

Props transition: Mengatur Durasi dan Easing

Props transition adalah tempat kamu mengontrol bagaimana animasi berjalan. Kamu bisa atur durasi, delay, tipe easing, dan banyak parameter lainnya. Secara default, Motion udah pake nilai yang bagus, tapi sering kali kamu mau customize sesuai kebutuhan.

Mari kita tambahkan transition ke contoh sebelumnya:

import { motion } from 'motion/react'

function SmoothCard() {
  return (
    <motion.div
      initial={{ opacity: 0, y: 50 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{
        duration: 0.6,
        ease: "easeOut"
      }}
      className="card"
    >
      <h2>Card dengan Transisi Custom</h2>
      <p>Animasi ini lebih lambat dan halus</p>
    </motion.div>
  )
}

export default SmoothCard

SmoothCard Animation
SmoothCard Animation

Di sini kita set duration: 0.6 yang berarti animasi bakal berjalan selama 0.6 detik (600 milidetik). Kamu bisa adjust ini sesuai kebutuhan. Animasi cepat biasanya 0.2-0.3 detik, medium 0.4-0.6 detik, dan slow 0.8-1.2 detik.

Property ease mengontrol kurva animasi. Ada beberapa pilihan umum:

  • "easeOut" - mulai cepat, akhir lambat (paling natural untuk entrance)
  • "easeIn" - mulai lambat, akhir cepat (bagus untuk exit)
  • "easeInOut" - lambat di awal dan akhir, cepat di tengah
  • "linear" - kecepatan konsisten (jarang dipake karena terasa robotik)

Kamu juga bisa tambah delay kalau mau animasi mulai setelah beberapa saat:

transition={{
  duration: 0.6,
  ease: "easeOut",
  delay: 0.2
}}

Delay berguna kalau kamu mau bikin efek stagger, dimana beberapa element muncul berurutan dengan jeda waktu.

Memahami Animation Lifecycle

Understanding animation lifecycle penting buat kamu bisa debug dan kontrol animasi dengan baik. Motion punya beberapa fase dalam lifecycle animasi:

1. Mount Phase (Initial State) Ketika component pertama kali di-render, element akan berada di state yang didefinisikan di props initial. Di fase ini, belum ada animasi yang terjadi. Element cuma di-render dengan nilai initial.

2. Animation Phase Segera setelah mount, Motion akan memulai animasi menuju state animate. Di fase ini, Motion menghitung semua frame intermediate dan update DOM setiap frame. Ini terjadi secara otomatis dan efficient, menggunakan requestAnimationFrame di browser.

3. Complete Phase Ketika animasi selesai, element akan berada di state animate dan tetap di sana sampai ada perubahan. Kamu bisa listen event ini dengan callback onAnimationComplete:

<motion.div
  initial={{ opacity: 0 }}
  animate={{ opacity: 1 }}
  transition={{ duration: 0.5 }}
  onAnimationComplete={() => {
    console.log('Animasi selesai!')
  }}
>
  Konten BuildWithAngga
</motion.div>

4. Re-animation Phase Kalau nilai di props animate berubah (misalnya karena state berubah), Motion secara otomatis bakal animasi dari kondisi sekarang ke kondisi baru. Ini sangat powerful karena kamu gak perlu manually handle transition antar state:

import { motion } from 'motion/react'
import { useState } from 'react'

function ToggleCard() {
  const [isExpanded, setIsExpanded] = useState(false)
  
  return (
    <motion.div
      animate={{ 
        height: isExpanded ? 'auto' : '120px',
        backgroundColor: isExpanded ? '#667eea' : '#764ba2'
      }}
      transition={{ duration: 0.4, ease: "easeInOut" }}
      className="expandable-card"
      onClick={() => setIsExpanded(!isExpanded)}
      style={{
        borderRadius: '16px',
        padding: '24px',
        cursor: 'pointer',
        color: 'white',
        boxShadow: '0 10px 30px rgba(0,0,0,0.2)'
      }}
    >
      <motion.h3
        animate={{ 
          scale: isExpanded ? 1.05 : 1,
          color: isExpanded ? '#fff' : '#f0f0f0'
        }}
        transition={{ duration: 0.3 }}
        style={{ margin: '0 0 12px 0', fontSize: '24px' }}
      >
        🚀 Kursus BuildWithAngga Premium
      </motion.h3>
      
      {isExpanded && (
        <motion.div
          initial={{ opacity: 0, y: -10 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 0.3, delay: 0.1 }}
        >
          <p style={{ margin: '12px 0', lineHeight: '1.6' }}>
            Dapatkan akses unlimited ke semua kursus web development, 
            mobile development, dan UI/UX design. Belajar dari mentor 
            berpengalaman dengan project real-world.
          </p>
          <motion.button
            whileHover={{ scale: 1.05 }}
            whileTap={{ scale: 0.95 }}
            style={{
              background: 'white',
              color: '#667eea',
              border: 'none',
              padding: '12px 24px',
              borderRadius: '8px',
              fontWeight: 'bold',
              cursor: 'pointer',
              marginTop: '12px'
            }}
          >
            Mulai Belajar Sekarang
          </motion.button>
        </motion.div>
      )}
      
      <motion.div
        animate={{ rotate: isExpanded ? 180 : 0 }}
        transition={{ duration: 0.3 }}
        style={{
          position: 'absolute',
          right: '24px',
          top: '24px',
          fontSize: '24px'
        }}
      >
        ▼
      </motion.div>
    </motion.div>
  )
}
Re-animation Phase
Re-animation Phase

Re-animation Phase

Di contoh ini, setiap kali isExpanded berubah, Motion otomatis animasi perubahan height dan background color. Kamu gak perlu mikirin keyframes atau manual calculation.

Debugging Animasi di Vite DevTools

Debugging animasi kadang tricky, tapi ada beberapa teknik yang bisa bantu kamu. Vite DevTools dan React DevTools adalah tool utama untuk debugging Motion animations.

Menggunakan Console Log

Cara paling simple adalah pake console.log di lifecycle callbacks:

<motion.div
  initial={{ opacity: 0 }}
  animate={{ opacity: 1 }}
  onAnimationStart={() => console.log('Animasi mulai')}
  onAnimationComplete={() => console.log('Animasi selesai')}
  onUpdate={(latest) => console.log('Nilai terkini:', latest)}
>
  Debug Card
</motion.div>

Debug Animasi
Debug Animasi

Callback onUpdate sangat berguna karena dipanggil setiap frame selama animasi, jadi kamu bisa lihat nilai-nilai intermediate.

Inspect Element di Browser

Buka DevTools browser (F12), pilih tab Elements, dan inspect element yang dianimasikan. Kamu bisa lihat perubahan inline style secara real-time waktu animasi berjalan. Ini berguna buat memastikan nilai-nilai yang kamu set benar-benar applied.

Slow Motion Animation

Kadang animasi terlalu cepat untuk di-debug. Kamu bisa temporary perlambat animasi dengan naikin durasi:

// Temporary untuk debugging
transition={{ duration: 2.0 }}  // Biasanya 0.5

Atau buat wrapper component yang otomatis slow down semua animasi di development:

const debugTransition = process.env.NODE_ENV === 'development'
  ? { duration: 2.0 }
  : { duration: 0.5 }

<motion.div
  initial={{ opacity: 0 }}
  animate={{ opacity: 1 }}
  transition={debugTransition}
>
  Konten
</motion.div>

React DevTools Components Tab

Install React DevTools extension di browser kamu. Dengan ini, kamu bisa inspect props dan state dari Motion components secara real-time. Kamu bisa lihat nilai animate dan initial yang currently active, dan track perubahan state yang trigger re-animation.

Common Issues dan Solusinya

Beberapa masalah umum yang sering terjadi:

  1. Animasi gak jalan sama sekali: Cek apakah kamu udah import motion dengan benar dan pastikan ada perbedaan antara nilai initial dan animate.
  2. Animasi janky atau patah-patah: Ini biasanya karena animating property yang gak di-optimize. Stick to transform properties (x, y, scale, rotate) dan opacity untuk performa terbaik.
  3. Layout shift: Kalau animasi bikin layout bergeser, consider pake position: absolute atau reserved space untuk element yang dianimasikan.
  4. Animasi terlalu cepet atau lambat: Adjust duration di transition. Sweet spot biasanya antara 0.3-0.6 detik untuk kebanyakan animasi.

Praktek Terbaik

Beberapa tips buat animasi yang lebih baik:

  • Jangan overuse animasi: Tidak semua element perlu animasi. Gunakan dengan bijak di tempat yang memang perlu emphasis atau feedback.
  • Stick to transform dan opacity: Dua property ini paling performa karena gak trigger layout recalculation. Avoid animating width, height, atau property lain yang trigger reflow.
  • Test di device berbeda: Animasi yang smooth di desktop kuat bisa jadi janky di mobile. Always test di berbagai device.
  • Consistent timing: Gunakan durasi yang konsisten untuk animasi sejenis di seluruh aplikasi. Ini bikin user experience lebih cohesive.

Sekarang kamu udah paham konsep dasar Motion! Di chapter selanjutnya, kita bakal eksplorasi teknik animasi yang lebih advanced dan bikin component yang lebih kompleks untuk project BuildWithAngga kita.

Animasi Dasar yang Wajib Dikuasai

Sekarang kita masuk ke praktek langsung bikin animasi yang sering banget dipake di project real-world. Di bagian ini, kita bakal belajar tiga jenis animasi fundamental yang wajib kamu kuasai: fade, slide, dan scale. Ketiga animasi ini adalah building blocks buat hampir semua animasi kompleks yang bakal kamu temuin nantinya.

A. Fade In/Out Animation

Implementasi dan Use Case

Fade animation adalah salah satu animasi paling umum dan paling sering dipake di web development. Konsepnya simpel: element muncul atau hilang dengan mengubah tingkat transparansi secara bertahap. Animasi ini smooth, elegan, dan gak bikin user overwhelmed.

Fade animation cocok dipake di banyak situasi. Misalnya waktu loading content dari API, showing/hiding modal, atau memunculkan notifikasi. Di BuildWithAngga, kamu bisa liat fade animation dipake buat memunculkan card kursus atau notification message. Cara kerjanya straightforward: kita ubah property opacity dari 0 (transparan) ke 1 (fully visible) atau sebaliknya.

Code Example dengan Motion

Mari kita implementasikan fade in animation buat component card:

import { motion } from 'motion/react'

interface CourseCardProps {
  title: string
  instructor: string
  price: string
}

function CourseCard({ title, instructor, price }: CourseCardProps) {
  return (
    <motion.div
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      transition={{ duration: 0.5 }}
      style={{
        padding: '24px',
        borderRadius: '12px',
        backgroundColor: 'white',
        boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
        marginBottom: '16px'
      }}
    >
      <h3 style={{ margin: '0 0 8px 0', color: '#333' }}>{title}</h3>
      <p style={{ margin: '0 0 12px 0', color: '#666' }}>
        Instruktur: {instructor}
      </p>
      <div style={{ fontSize: '20px', fontWeight: 'bold', color: '#667eea' }}>
        {price}
      </div>
    </motion.div>
  )
}

export default CourseCard

Fade In / Out Animation
Fade In / Out Animation

Buat toggle visibility berdasarkan state, kita bisa pake AnimatePresence:

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

function NotificationBanner() {
  const [isVisible, setIsVisible] = useState<boolean>(true)

  return (
    <div style={{ padding: '20px' }}>
      <button onClick={() => setIsVisible(!isVisible)}>
        Toggle Notifikasi
      </button>

      <AnimatePresence>
        {isVisible && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            transition={{ duration: 0.3 }}
            style={{
              marginTop: '16px',
              padding: '16px',
              backgroundColor: '#667eea',
              color: 'white',
              borderRadius: '8px'
            }}
          >
            Selamat! Kamu berhasil menyelesaikan kursus
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  )
}

Toggle Visiblity
Toggle Visiblity

Perhatiin kita pake AnimatePresence wrapper dan props exit. Ini penting buat animasi unmount. Tanpa ini, element bakal langsung hilang tanpa animasi fade out.

Testing di Vite Dev Server

Setelah kamu tulis code di atas, save file nya dan liat hasil di browser. Vite langsung update tanpa perlu refresh. Coba klik button toggle beberapa kali dan perhatikan animasi fade in dan fade out nya. Kalau animasi terlalu cepat atau lambat, adjust nilai duration sampai dapet feel yang pas.

B. Slide Animation

Dari Berbagai Arah

Slide animation adalah animasi dimana element bergerak masuk atau keluar dari berbagai arah. Ini sangat populer buat modal, sidebar, atau navigation menu. Motion menggunakan property x dan y buat mengontrol posisi:

  • y: -50 = dari atas (top)
  • y: 50 = dari bawah (bottom)
  • x: -50 = dari kiri (left)
  • x: 50 = dari kanan (right)

Nilai nya dalam pixel. Makin besar angkanya, makin jauh element bergerak. Biasanya kita pake nilai antara 20-100 pixel buat slide animation yang natural.

Code Example

import { motion } from 'motion/react'
import type { CSSProperties } from 'react'

// Slide dari atas
function SlideFromTop() {
  const cardStyle: CSSProperties = {
    padding: '20px',
    backgroundColor: '#667eea',
    color: 'white',
    borderRadius: '8px',
    marginBottom: '16px'
  }

  return (
    <motion.div
      initial={{ y: -100, opacity: 0 }}
      animate={{ y: 0, opacity: 1 }}
      transition={{ duration: 0.5, ease: "easeOut" }}
      style={cardStyle}
    >
      Slide dari Atas - Header Navigation
    </motion.div>
  )
}

// Slide dari bawah
function SlideFromBottom() {
  const cardStyle: CSSProperties = {
    padding: '20px',
    backgroundColor: '#764ba2',
    color: 'white',
    borderRadius: '8px',
    marginBottom: '16px'
  }

  return (
    <motion.div
      initial={{ y: 100, opacity: 0 }}
      animate={{ y: 0, opacity: 1 }}
      transition={{ duration: 0.5, ease: "easeOut" }}
      style={cardStyle}
    >
      Slide dari Bawah - Footer Content
    </motion.div>
  )
}

// Slide dari kiri
function SlideFromLeft() {
  const cardStyle: CSSProperties = {
    padding: '20px',
    backgroundColor: '#f093fb',
    color: 'white',
    borderRadius: '8px',
    marginBottom: '16px'
  }

  return (
    <motion.div
      initial={{ x: -100, opacity: 0 }}
      animate={{ x: 0, opacity: 1 }}
      transition={{ duration: 0.5, ease: "easeOut" }}
      style={cardStyle}
    >
      Slide dari Kiri - Sidebar Menu
    </motion.div>
  )
}

// Slide dari kanan
function SlideFromRight() {
  const cardStyle: CSSProperties = {
    padding: '20px',
    backgroundColor: '#4facfe',
    color: 'white',
    borderRadius: '8px'
  }

  return (
    <motion.div
      initial={{ x: 100, opacity: 0 }}
      animate={{ x: 0, opacity: 1 }}
      transition={{ duration: 0.5, ease: "easeOut" }}
      style={cardStyle}
    >
      Slide dari Kanan - Notification Panel
    </motion.div>
  )
}

// Component utama
function SlideExamples() {
  return (
    <div style={{ padding: '20px', maxWidth: '600px' }}>
      <h2>Contoh Slide Animation</h2>
      <SlideFromTop />
      <SlideFromBottom />
      <SlideFromLeft />
      <SlideFromRight />
    </div>
  )
}

export default SlideExamples

Slide Animation
Slide Animation

Perhatiin kita kombinasiin slide dengan fade (opacity). Ini teknik umum yang bikin animasi lebih smooth dan profesional.

Membuat Reusable Slide Component

Daripada bikin component terpisah buat setiap arah, lebih baik bikin satu reusable component:

import { motion } from 'motion/react'
import type { ReactNode } from 'react'

type Direction = 'top' | 'bottom' | 'left' | 'right'

interface SlideInProps {
  children: ReactNode
  direction?: Direction
  delay?: number
  duration?: number
}

function SlideIn({
  children,
  direction = 'bottom',
  delay = 0,
  duration = 0.5
}: SlideInProps) {
  // Tentukan initial position berdasarkan direction
  const directions: Record<Direction, { y: number; x: number }> = {
    top: { y: -100, x: 0 },
    bottom: { y: 100, x: 0 },
    left: { x: -100, y: 0 },
    right: { x: 100, y: 0 }
  }

  const initial = {
    ...directions[direction],
    opacity: 0
  }

  return (
    <motion.div
      initial={initial}
      animate={{ x: 0, y: 0, opacity: 1 }}
      transition={{
        duration: duration,
        delay: delay,
        ease: "easeOut"
      }}
    >
      {children}
    </motion.div>
  )
}

// Cara pakainya
function BuildWithAnggaHero() {
  const buttonStyle: React.CSSProperties = {
    padding: '16px 32px',
    fontSize: '18px',
    backgroundColor: '#667eea',
    color: 'white',
    border: 'none',
    borderRadius: '8px',
    cursor: 'pointer'
  }

  return (
    <div style={{ padding: '40px', textAlign: 'center' }}>
      <SlideIn direction="top">
        <h1 style={{ fontSize: '48px', marginBottom: '16px' }}>
          BuildWithAngga
        </h1>
      </SlideIn>

      <SlideIn direction="left" delay={0.2}>
        <p style={{ fontSize: '20px', color: '#666', marginBottom: '24px' }}>
          Platform belajar coding terbaik di Indonesia
        </p>
      </SlideIn>

      <SlideIn direction="right" delay={0.4}>
        <button style={buttonStyle}>
          Mulai Belajar Gratis
        </button>
      </SlideIn>
    </div>
  )
}

export default BuildWithAnggaHero

Reusebale Slide Component
Reusebale Slide Component

Component SlideIn ini super flexible. Kamu bisa atur arah, delay, dan durasi sesuai kebutuhan. Perhatiin kita pake staggered delay (0, 0.2, 0.4) buat bikin efek berurutan yang smooth.

C. Scale Animation

Hover Effect dan Emphasis

Scale animation adalah animasi yang mengubah ukuran element. Ini sangat efektif buat emphasis, hover effects, atau call-to-action buttons. Scale animation paling sering dipake buat hover effect pada button, card, atau interactive elements. User hover mouse ke element, element jadi sedikit lebih besar, dan ini kasih feedback bahwa element tersebut clickable.

Code Example

import { motion } from 'motion/react'
import type { ReactNode } from 'react'

interface ScaleButtonProps {
  children: ReactNode
  onClick?: () => void
}

function ScaleButton({ children, onClick }: ScaleButtonProps) {
  return (
    <motion.button
      whileHover={{ scale: 1.05 }}
      whileTap={{ scale: 0.95 }}
      transition={{ duration: 0.2 }}
      onClick={onClick}
      style={{
        padding: '16px 32px',
        fontSize: '16px',
        backgroundColor: '#667eea',
        color: 'white',
        border: 'none',
        borderRadius: '8px',
        cursor: 'pointer',
        fontWeight: 'bold'
      }}
    >
      {children}
    </motion.button>
  )
}

interface CourseCardProps {
  title: string
  price: string
}

function CourseCardWithHover({ title, price }: CourseCardProps) {
  return (
    <motion.div
      whileHover={{
        scale: 1.03,
        boxShadow: '0 8px 24px rgba(0,0,0,0.15)'
      }}
      transition={{ duration: 0.3 }}
      style={{
        padding: '20px',
        backgroundColor: 'white',
        borderRadius: '12px',
        boxShadow: '0 4px 12px rgba(0,0,0,0.08)',
        cursor: 'pointer'
      }}
    >
      <div style={{
        width: '100%',
        height: '160px',
        backgroundColor: '#f0f0f0',
        borderRadius: '8px',
        marginBottom: '16px'
      }} />
      <h3 style={{ margin: '0 0 8px 0' }}>{title}</h3>
      <p style={{
        fontSize: '20px',
        fontWeight: 'bold',
        color: '#667eea',
        margin: 0
      }}>
        {price}
      </p>
    </motion.div>
  )
}

export { ScaleButton, CourseCardWithHover }

Scale Animation
Scale Animation

Perhatiin kita pake whileHover dan whileTap - ini adalah shorthand props yang sangat convenient buat interactive animations. Gak perlu track state manual, Motion handle semuanya.

Combining dengan State React

Sekarang mari kita bikin contoh yang lebih kompleks, combining scale animation dengan React state:

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

function LikeButton() {
  const [isLiked, setIsLiked] = useState<boolean>(false)
  const [likeCount, setLikeCount] = useState<number>(42)

  const handleLike = (): void => {
    if (!isLiked) {
      setLikeCount(likeCount + 1)
    } else {
      setLikeCount(likeCount - 1)
    }
    setIsLiked(!isLiked)
  }

  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: '12px', marginBottom: '20px' }}>
      <motion.button
        whileHover={{ scale: 1.1 }}
        whileTap={{ scale: 0.9 }}
        onClick={handleLike}
        style={{
          width: '48px',
          height: '48px',
          borderRadius: '100%',
          border: 'none',
          backgroundColor: '#242424',
          cursor: 'pointer',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          outline: 'none',
          fontSize: '24px',
          transition: 'background-color 0.3s'
        }}
      >
        <AnimatePresence mode="wait">
          <motion.span
            key={isLiked ? 'liked' : 'unliked'}
            initial={{ scale: 0 }}
            animate={{ scale: 1 }}
            exit={{ scale: 0 }}
            transition={{ duration: 0.2 }}
          >
            {isLiked ? '❤️' : '🤍'}
          </motion.span>
        </AnimatePresence>
      </motion.button>

      <motion.span
        key={likeCount}
        initial={{ scale: 1.5, color: '#ef4444' }}
        animate={{ scale: 1, color: '#ffffffde' }}
        style={{ fontSize: '18px', fontWeight: 'bold' }}
      >
        {likeCount} likes
      </motion.span>
    </div>
  )
}

function AddToCartButton() {
  const [isAdded, setIsAdded] = useState<boolean>(false)

  const handleAddToCart = (): void => {
    setIsAdded(true)
    setTimeout(() => setIsAdded(false), 2000)
  }

  return (
    <motion.button
      whileHover={{ scale: 1.05 }}
      whileTap={{ scale: 0.95 }}
      animate={{ backgroundColor: isAdded ? '#10b981' : '#667eea' }}
      onClick={handleAddToCart}
      style={{
        padding: '14px 28px',
        fontSize: '16px',
        color: 'white',
        border: 'none',
        borderRadius: '8px',
        cursor: isAdded ? 'default' : 'pointer',
        fontWeight: 'bold'
      }}
    >
      <AnimatePresence mode="wait">
        {isAdded ? (
          <motion.span
            key="added"
            initial={{ y: 20, opacity: 0 }}
            animate={{ y: 0, opacity: 1 }}
            exit={{ y: -20, opacity: 0 }}
          >
            ✓ Ditambahkan ke Keranjang
          </motion.span>
        ) : (
          <motion.span
            key="add"
            initial={{ y: 20, opacity: 0 }}
            animate={{ y: 0, opacity: 1 }}
            exit={{ y: -20, opacity: 0 }}
          >
            Tambah ke Keranjang
          </motion.span>
        )}
      </AnimatePresence>
    </motion.button>
  )
}

export { LikeButton, AddToCartButton }

Combining with State React
Combining with State React

Di contoh ini, kita combining beberapa teknik: scale animation pada hover dan tap, state management buat track user interaction, AnimatePresence buat smooth transition antar state, color animation buat visual feedback, dan text slide animation buat button state change. Ini pattern yang sangat umum dipake di real-world applications.

Tips dan Best Practices

Performance Optimization

Stick ke transform properties (scale, x, y, rotate) dan opacity karena ini paling performant. Browser bisa optimize animasi ini pake GPU acceleration. Hindari animating width, height, atau property lain yang trigger layout recalculation.

Timing yang Tepat

Fade: 0.3-0.5 detik untuk kebanyakan kasus. Slide: 0.4-0.6 detik, pake ease-out buat feel natural. Scale: 0.2-0.3 detik, lebih cepat karena movement lebih subtle.

Kombinasi Animasi

Jangan takut combine multiple animations. Fade + slide atau scale + fade sering menghasilkan efek yang lebih menarik dibanding single animation. Tapi jangan overdo it - keep it simple and purposeful.

Testing di Berbagai Device

Animasi yang smooth di desktop mungkin janky di mobile. Always test di device dengan spesifikasi lebih rendah. Kalau perlu, buat conditional animation yang lebih simple buat mobile.

Sekarang kamu udah menguasai tiga animasi fundamental! Practice bikin component-component ini dan experiment dengan nilai-nilai yang berbeda. Di chapter selanjutnya, kita bakal explore animasi yang lebih advanced seperti stagger, gestures, dan scroll-based animations.

Gesture dan Interaksi

Di bagian ini, kita bakal belajar gimana cara bikin component yang responsif terhadap interaksi user seperti hover, click, dan drag. Motion bikin semua ini jadi super mudah dengan props khusus yang tinggal pake.

Hover Animations dengan whileHover

Hover animation kasih feedback visual waktu user arahkan mouse ke element. Motion punya props whileHover yang bikin ini jadi gampang banget. Begitu mouse keluar, animasi otomatis balik ke normal.

import { motion } from 'motion/react'

function CourseCard() {
  return (
    <motion.div
      whileHover={{
        scale: 1.05,
        boxShadow: '0 10px 30px rgba(0,0,0,0.2)'
      }}
      transition={{ duration: 0.3 }}
      style={{
        padding: '24px',
        backgroundColor: 'white',
        borderRadius: '12px',
        boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
        cursor: 'pointer',
        width: '300px'
      }}
    >
      <h3 style={{ margin: '0 0 8px 0', color: '#333' }}>
        Kursus React Advanced
      </h3>
      <p style={{ margin: '0', color: '#666' }}>
        Pelajari React dari dasar hingga mahir di BuildWithAngga
      </p>
    </motion.div>
  )
}

export default CourseCard

Contoh di atas bikin card sedikit membesar (scale 1.05) dan shadow-nya lebih jelas waktu di-hover. Simple tapi effective! Kamu bisa pake whileHover di elemen apapun: button, card, image, atau apapun yang mau kamu bikin interactive.

Hover Animation
Hover Animation

Tap Animations dengan whileTap

Props whileTap trigger waktu user klik element. Biasanya pake scale yang lebih kecil buat simulate effect "menekan" button.

import { motion } from 'motion/react'

function ActionButton() {
  return (
    <motion.button
      whileHover={{ scale: 1.05 }}
      whileTap={{ scale: 0.95 }}
      transition={{ duration: 0.2 }}
      onClick={() => alert('Button diklik!')}
      style={{
        padding: '14px 28px',
        fontSize: '16px',
        color: 'white',
        border: 'none',
        borderRadius: '8px',
        cursor: 'pointer',
        fontWeight: 'bold',
        backgroundColor: '#667eea'
      }}
    >
      Daftar Kursus BuildWithAngga
    </motion.button>
  )
}

export default ActionButton

Tap Animation
Tap Animation

Kombinasi whileHover (scale 1.05) dan whileTap (scale 0.95) kasih feedback yang jelas: hover show button interactive, tap confirm action berhasil. Ini pattern yang paling umum dipake buat button di web modern.

Drag Interactions

Motion bikin element jadi draggable dengan satu prop: drag. Kamu juga bisa set batasan area drag dengan dragConstraints.

import { motion } from 'motion/react'
import { useRef } from 'react'

function DragExample() {
  const constraintsRef = useRef<HTMLDivElement>(null)

  return (
    <div
      ref={constraintsRef}
      style={{
        width: '400px',
        height: '400px',
        backgroundColor: '#f3f4f6',
        borderRadius: '12px',
        padding: '20px',
        position: 'relative'
      }}
    >
      <motion.div
        drag
        dragConstraints={constraintsRef}
        dragElastic={0.1}
        whileHover={{ scale: 1.1 }}
        whileTap={{ scale: 0.9 }}
        style={{
          width: '120px',
          height: '120px',
          backgroundColor: '#667eea',
          borderRadius: '12px',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          color: 'white',
          fontWeight: 'bold',
          cursor: 'grab'
        }}
      >
        Drag Me!
      </motion.div>
    </div>
  )
}

export default DragExample

Draggable Animation
Draggable Animation

Props drag enable dragging ke semua arah. Props dragConstraints dengan ref bikin element cuma bisa di-drag dalam container. dragElastic={0.1} kasih sedikit "bounce" waktu mencapai batas. Kalau mau restrict ke satu axis, pake drag="x" atau drag="y".

Contoh Praktis: Interactive Button Component

Mari combine semua fitur jadi satu button component yang production-ready:

import { motion } from 'motion/react'
import { useState } from 'react'

interface InteractiveButtonProps {
  children: React.ReactNode
  onClick?: () => void
  isLoading?: boolean
}

function InteractiveButton({
  children,
  onClick,
  isLoading = false
}: InteractiveButtonProps) {
  return (
    <motion.button
      whileHover={!isLoading ? { scale: 1.05 } : {}}
      whileTap={!isLoading ? { scale: 0.95 } : {}}
      transition={{ duration: 0.2 }}
      onClick={onClick}
      style={{
        backgroundColor: '#667eea',
        color: 'white',
        padding: '14px 28px',
        fontSize: '16px',
        border: 'none',
        borderRadius: '8px',
        cursor: isLoading ? 'wait' : 'pointer',
        fontWeight: 'bold',
        minWidth: '200px'
      }}
    >
      {isLoading ? (
        <motion.div
          animate={{ rotate: 360 }}
          transition={{ duration: 1, repeat: Infinity, ease: 'linear' }}
          style={{
            width: '20px',
            height: '20px',
            border: '3px solid rgba(255,255,255,0.3)',
            borderTopColor: 'white',
            borderRadius: '50%',
            display: 'inline-block'
          }}
        />
      ) : (
        children
      )}
    </motion.button>
  )
}

// Cara pakainya
function ButtonDemo() {
  const [isLoading, setIsLoading] = useState(false)

  const handleSubmit = () => {
    setIsLoading(true)
    // Simulasi API call
    setTimeout(() => {
      setIsLoading(false)
      alert('Pendaftaran berhasil!')
    }, 2000)
  }

  return (
    <div style={{ padding: '40px' }}>
      <InteractiveButton onClick={handleSubmit} isLoading={isLoading}>
        Daftar Kursus BuildWithAngga
      </InteractiveButton>
    </div>
  )
}

export default ButtonDemo

Interactive Button
Interactive Button

Component ini combine hover, tap, dan loading state. Waktu loading, animasi hover/tap dinonaktifkan dan muncul spinning loader. Ini pattern yang sering banget dipake di real-world applications.

Hot Reload Testing dengan Vite

Vite punya hot reload yang super cepat, perfect buat testing interactive components.

Testing Workflow:

  1. Jalankan npm run dev
  2. Buka browser di http://localhost:5173
  3. Buka code editor dan browser berdampingan
  4. Ubah nilai animasi di code (misal: scale: 1.05 jadi scale: 1.1)
  5. Save file - perubahan langsung keliatan di browser

Tips Testing:

  • Scale value: Test antara 1.02 sampai 1.1 buat hover, cari yang paling natural
  • Duration: Coba 0.2 sampai 0.4 detik
  • Performance: Buka DevTools, pastikan smooth 60fps

Quick Debug:

Tambah console.log buat track events:

<motion.button
  whileHover={{ scale: 1.05 }}
  onHoverStart={() => console.log('Hover mulai')}
  onTap={() => console.log('Diklik')}
>
  Debug Button
</motion.button>

Sekarang kamu udah paham gesture dan interaksi di Motion! Coba bikin component interactive sendiri dan experiment dengan values yang berbeda. Start simple, terus tambah complexity seiring kamu makin nyaman.

Penutup

Selamat! Kamu udah berhasil mempelajari dasar-dasar Motion dan gimana cara mengintegrasikannya dengan Vite. Dari setup project, konsep fundamental seperti initial, animate, dan transition, sampai animasi dasar kayak fade, slide, dan scale. Kamu juga udah belajar bikin component interactive dengan hover, tap, dan drag interactions.

Yang penting sekarang adalah latihan. Mulai dari component sederhana, terus secara bertahap tingkatkan kompleksitasnya. Jangan takut bereksperimen dengan nilai-nilai animasi yang berbeda sampai dapet feel yang pas. Ingat, animasi yang bagus bukan tentang seberapa mewah atau kompleks, tapi tentang seberapa baik dia meningkatkan pengalaman pengguna.

Belajar di Kelas BuildWithAngga

Kalau kamu mau memperdalam pengetahuan tentang React, animasi, dan web development, BuildWithAngga punya banyak kelas yang bisa bantu kamu naik level. Platform ini menawarkan kursus dengan pembelajaran berbasis project, jadi kamu gak cuma belajar teori tapi langsung praktek bikin aplikasi dunia nyata.

Di BuildWithAngga, kamu bisa belajar dari mentor berpengalaman yang udah kerja di industri. Materinya selalu update mengikuti teknologi terbaru, termasuk React, TypeScript, dan tools modern kayak Vite. Plus, setelah selesai kursus, kamu dapet sertifikat yang bisa kamu pake buat portfolio atau lamaran kerja.

Jangan lupa join komunitas BuildWithAngga dan terus latihan apa yang udah kamu pelajari. Selamat coding, dan semoga artikel ini bermanfaat!