Tips & Tricks (Diperbarui: 2/6/2026)

Claude Code dan Framer Motion: panduan praktis Motion for React

Gunakan Claude Code dengan Framer Motion/Motion for React: prompt, contoh TSX, pitfall, aksesibilitas, dan verifikasi.

Claude Code dan Framer Motion: panduan praktis Motion for React

Banyak developer masih mencari dengan nama Framer Motion, tetapi dokumentasi resmi terbaru menyebut library ini sebagai Motion for React. Untuk kode baru, install motion dan import API React dari motion/react. Jika aplikasi lama sudah konsisten memakai framer-motion, jangan mencampur kedua gaya import tanpa keputusan tim. Untuk implementasi baru, jadikan dokumentasi resmi Motion for React sebagai acuan.

Claude Code bisa mempercepat pekerjaan animasi, tetapi tidak otomatis memahami konteks produk. Prompt seperti “buat lebih smooth” sering menghasilkan gerakan terlalu ramai, melewatkan Reduced Motion, atau membuat exit animation gagal karena parent component unmount terlalu cepat. Masa mencoba pola ini di dashboard internal: versi pertama tampak bagus saat demo, tetapi card bergerak terlalu jauh, notification hilang tanpa exit, dan header berbasis scroll terasa berat di laptop sederhana.

Artikel ini memperlakukan Claude Code sebagai kolaborator yang perlu batas jelas. Kita tentukan intent, scope, aksesibilitas, dan cara verifikasi sebelum meminta perubahan kode. Contoh TSX di bawah bisa ditempel ke proyek React setelah npm install motion. Untuk Next.js atau Astro, simpan bagian ini sebagai client component.

Mulai dari batas desain

Animasi bukan dekorasi. Animasi harus menjelaskan perubahan state. Sebelum memberi tugas ke Claude Code, tulis batasnya.

KeputusanYang diberikan ke Claude CodeYang direview
TujuanState change mana yang perlu dibantuAnimasi membantu pemahaman
ScopeFile yang boleh dan tidak boleh disentuhTidak ada refactor yang tidak terkait
APImotion/react dan Reduced MotionImport dan behavior sesuai docs
VerifikasiManual test, keyboard, device lambatTest mengikuti alur nyata user

Alurnya bisa dibuat sederhana:

Intent dan batasan
  -> prompt Claude Code
  -> implementasi Motion for React
  -> verifikasi manual dan aksesibilitas
  -> prompt lanjutan yang spesifik

Prompt pertama yang praktis:

Tambahkan animasi Motion for React ke React component yang sudah ada.
Syarat:
- Import API Motion baru dari `motion/react`
- Jangan ubah data fetching, form submit, atau routing
- Dukung Reduced Motion
- Prioritaskan opacity dan transform
- Hindari layout shift
- Sertakan checklist manual test setelah perubahan

Detail import penting karena banyak contoh lama masih memakai framer-motion. Jika standar repo tidak ditulis, Claude Code mudah mengambil pola yang tidak konsisten.

Use case 1: daftar card yang masuk natural

Dashboard, daftar artikel, dan feature card cocok memakai stagger yang tenang. Tujuannya bukan membuat setiap card terlihat spektakuler, tetapi memberi urutan baca. Dalam pengujian Masa, stagger 0,06 sampai 0,09 detik terasa pas untuk enam card; lebih lama dari itu membuat UI terasa menunggu.

import { motion, useReducedMotion } from "motion/react";

type Feature = {
  id: string;
  title: string;
  body: string;
  metric: string;
};

const demoFeatures: Feature[] = [
  {
    id: "review",
    title: "Antrian review",
    body: "Perubahan dari Claude Code yang perlu dicek manusia.",
    metric: "8 item",
  },
  {
    id: "motion",
    title: "Perbaikan motion",
    body: "Transisi pendek menjelaskan perubahan tanpa memperlambat kerja.",
    metric: "14%",
  },
  {
    id: "a11y",
    title: "Reduced Motion",
    body: "Gerakan besar berubah menjadi fade yang lebih tenang.",
    metric: "Siap",
  },
];

export function AnimatedFeatureCards({
  items = demoFeatures,
}: {
  items?: Feature[];
}) {
  const shouldReduceMotion = useReducedMotion();

  const container = {
    hidden: { opacity: 0 },
    visible: {
      opacity: 1,
      transition: {
        staggerChildren: shouldReduceMotion ? 0 : 0.08,
      },
    },
  };

  const card = {
    hidden: {
      opacity: 0,
      y: shouldReduceMotion ? 0 : 16,
    },
    visible: {
      opacity: 1,
      y: 0,
      transition: {
        duration: 0.32,
        ease: "easeOut",
      },
    },
  };

  return (
    <motion.section
      aria-label="Feature cards"
      variants={container}
      initial="hidden"
      animate="visible"
      style={{
        display: "grid",
        gap: 16,
        gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))",
      }}
    >
      {items.map((item) => (
        <motion.article
          key={item.id}
          variants={card}
          whileHover={shouldReduceMotion ? undefined : { y: -4 }}
          style={{
            border: "1px solid #d9e2ec",
            borderRadius: 12,
            padding: 20,
            background: "#ffffff",
            boxShadow: "0 8px 24px rgba(15, 23, 42, 0.08)",
          }}
        >
          <p style={{ margin: 0, color: "#2563eb", fontWeight: 700 }}>
            {item.metric}
          </p>
          <h3 style={{ margin: "8px 0", fontSize: 18 }}>{item.title}</h3>
          <p style={{ margin: 0, lineHeight: 1.7, color: "#475569" }}>
            {item.body}
          </p>
        </motion.article>
      ))}
    </motion.section>
  );
}

Review tiga hal: key stabil, gerakan memakai transform, dan Reduced Motion menghilangkan perpindahan besar. Prompt lanjutan yang baik: “Pertahankan stagger, tetapi daftar harus tetap langsung bisa digunakan saat ada 12 card.”

Use case 2: notification dengan exit animation

AnimatePresence membuat element tetap bisa dianimasikan ketika keluar dari React tree. Dokumentasi AnimatePresence menekankan bahwa direct children membutuhkan key stabil. Kesalahan umum adalah membuat seluruh container notification conditional, sehingga parent hilang sebelum child menjalankan exit.

import { useState } from "react";
import { AnimatePresence, motion } from "motion/react";

type Toast = {
  id: number;
  message: string;
};

let nextToastId = 1;

export function AnimatedNotifications() {
  const [toasts, setToasts] = useState<Toast[]>([
    { id: 0, message: "Berhasil disimpan" },
  ]);

  function addToast() {
    const id = nextToastId++;
    setToasts((current) => [
      ...current,
      { id, message: `Background job ${id} selesai` },
    ]);
  }

  function dismissToast(id: number) {
    setToasts((current) => current.filter((toast) => toast.id !== id));
  }

  return (
    <div>
      <button type="button" onClick={addToast}>
        Tambah notification
      </button>

      <div
        aria-live="polite"
        style={{
          position: "fixed",
          right: 24,
          top: 24,
          display: "grid",
          gap: 12,
          width: "min(360px, calc(100vw - 48px))",
        }}
      >
        <AnimatePresence initial={false} mode="popLayout">
          {toasts.map((toast) => (
            <motion.div
              layout
              key={toast.id}
              initial={{ opacity: 0, x: 40, scale: 0.96 }}
              animate={{ opacity: 1, x: 0, scale: 1 }}
              exit={{ opacity: 0, x: 40, scale: 0.96 }}
              transition={{ duration: 0.2, ease: "easeOut" }}
              style={{
                borderRadius: 10,
                border: "1px solid #cbd5e1",
                background: "#ffffff",
                padding: 16,
                boxShadow: "0 12px 30px rgba(15, 23, 42, 0.16)",
              }}
            >
              <p style={{ margin: "0 0 12px", color: "#0f172a" }}>
                {toast.message}
              </p>
              <button type="button" onClick={() => dismissToast(toast.id)}>
                Tutup
              </button>
            </motion.div>
          ))}
        </AnimatePresence>
      </div>
    </div>
  );
}

Minta Claude Code memeriksa apakah container tetap mounted saat tidak ada notification, tombol bisa dipakai dengan keyboard, dan aria-live tidak terlalu ramai. Notification muncul berulang selama sesi kerja, jadi perilaku yang tenang lebih penting daripada efek visual.

Use case 3: progress baca dengan scroll

Dokumentasi panjang, onboarding, dan landing page sering butuh orientasi. useScroll memberi progress halaman atau element sebagai MotionValue. Dengan useSpring, progress bar terasa lebih stabil. Jangan ubah semua section menjadi parallax; saat Reduced Motion aktif, hilangkan perpindahan besar.

import { useRef } from "react";
import {
  motion,
  useReducedMotion,
  useScroll,
  useSpring,
  useTransform,
} from "motion/react";

const sections = [
  {
    title: "Kunci requirement",
    body: "Sebelum Claude Code mengedit, tulis tujuan, target file, dan batasan.",
  },
  {
    title: "Gerakkan sedikit",
    body: "Mulai dari opacity dan transform agar motion membantu pemahaman.",
  },
  {
    title: "Verifikasi alur nyata",
    body: "Cek device lambat, keyboard, dan Reduced Motion sebelum publish.",
  },
];

export function ScrollReadingProgress() {
  const articleRef = useRef<HTMLElement | null>(null);
  const shouldReduceMotion = useReducedMotion();
  const { scrollYProgress } = useScroll({
    target: articleRef,
    offset: ["start start", "end end"],
  });

  const scaleX = useSpring(scrollYProgress, {
    stiffness: 120,
    damping: 28,
    mass: 0.2,
  });
  const y = useTransform(scrollYProgress, [0, 1], [0, -48]);

  return (
    <article ref={articleRef} style={{ position: "relative", padding: 24 }}>
      <motion.div
        aria-hidden="true"
        style={{
          position: "sticky",
          top: 0,
          zIndex: 10,
          height: 4,
          scaleX: shouldReduceMotion ? 1 : scaleX,
          transformOrigin: "0% 50%",
          background: "#2563eb",
        }}
      />

      <motion.header
        style={{
          y: shouldReduceMotion ? 0 : y,
          padding: "56px 0 32px",
        }}
      >
        <p style={{ color: "#2563eb", fontWeight: 700 }}>
          Claude Code x Motion
        </p>
        <h2 style={{ fontSize: 36, margin: 0 }}>
          Halaman yang membuka konteks saat dibaca
        </h2>
      </motion.header>

      <div style={{ display: "grid", gap: 24 }}>
        {sections.map((section) => (
          <section
            key={section.title}
            style={{
              border: "1px solid #dbe4ee",
              borderRadius: 12,
              padding: 24,
              background: "#ffffff",
            }}
          >
            <h3>{section.title}</h3>
            <p style={{ lineHeight: 1.8 }}>{section.body}</p>
          </section>
        ))}
      </div>
    </article>
  );
}

Pakai pola ini untuk orientasi, bukan untuk mengisi ruang kosong. Satu progress bar yang jelas biasanya lebih berguna daripada banyak scroll reveal yang membuat halaman terasa lambat.

Jadikan Claude Code reviewer

Setelah implementasi, minta review kritis dengan daftar failure mode.

Review diff saat ini sebagai implementasi Motion for React.
Periksa dengan ketat:
- Tidak mencampur `motion/react` dan import lama `framer-motion`
- Direct children dari `AnimatePresence` punya key stabil
- Reduced Motion mematikan gerakan besar, parallax, dan efek seperti autoplay
- Kode tidak sering menganimasikan width, height, top, atau left
- Manual test mengikuti aksi nyata user

Prompt ini membuat Claude Code bukan hanya generator, tetapi juga reviewer pertama. Karena bisa membaca file sekitar, ia dapat menemukan konflik CSS, perubahan state yang tidak diinginkan, dan test yang belum ada.

Pitfall dan checklist

Pitfall pertama adalah import lama. Pada legacy project, framer-motion bisa tetap benar, tetapi kode baru sebaiknya mengikuti motion dan motion/react kecuali repo memutuskan lain. Pitfall kedua adalah mengira exit rusak karena easing. Biasanya masalahnya ada di React tree: parent unmount terlalu cepat, key memakai index, atau item tidak keluar dari dalam AnimatePresence.

Pitfall ketiga adalah terlalu percaya pada layout. Fitur ini membantu reorder dan perubahan ukuran, tetapi image tanpa dimensi, font yang terlambat load, dan perubahan Grid mendadak masih bisa membuat elemen meloncat. Pitfall keempat adalah menunda aksesibilitas. Panduan resmi accessibility menjelaskan Reduced Motion; jika desain memakai gerakan besar, parallax, atau efek mirip autoplay, jalur alternatif harus ada sejak versi pertama.

Sebelum publish, pastikan: docs resmi dan import cocok, setiap animasi punya tujuan produk, Reduced Motion menghapus gerakan besar, children AnimatePresence memiliki key, keyboard dan focus tetap bekerja, dan efek scroll tidak mengganggu keterbacaan.

Untuk fondasi UI, baca Radix UI dengan Claude Code, shadcn/ui dengan Claude Code, dan panduan animasi Claude Code. Untuk agent-nya sendiri, lihat dokumentasi Claude Code dari Anthropic.

Kesimpulan

Menggabungkan Claude Code dan Framer Motion bukan hanya soal menulis animasi lebih cepat. Nilai utamanya adalah membawa implementasi, aksesibilitas, dan review criteria ke satu workflow sebelum UI dirilis.

Hasil praktik Masa cukup jelas: menulis motion/react, Reduced Motion, dan manual verification di prompt pertama mengurangi rework lebih banyak daripada polishing setelahnya. Untuk menyimpan template prompt, gunakan cheat sheet gratis. Jika ingin mereview beberapa layar bersama tim, halaman training dan konsultasi adalah langkah berikutnya yang realistis.

#Claude Code #Framer Motion #Motion for React #React #animasi #UI/UX
Gratis

PDF gratis: cheatsheet Claude Code

Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.

Kami menjaga datamu dan tidak mengirim spam.

Masa

Tentang penulis

Masa

Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.