Skip to content

The Edge of the Cyber World See the latest

Apps

React vs Vue Animation: Motion vs GSAP in 12 Steps [2026]

Type “framer motion vs gsap” into Google in August 2026 and you will land on a debate that has quietly reshaped how front-end teams pick their animation stack. Framer Motion renamed itself Motion in early 2025, expanded past React into a framework-agnostic library, and now competes directly with GSAP on turf GSAP owned for over a decade: scroll storytelling, timelines, and drag interactions. Meanwhile GSAP shipped version 3.15 in April 2026 and made every plugin free, including the ones that used to sit behind a Club GreenSock paywall. If you build in React, Vue, or both, the animation layer you choose now affects bundle size, accessibility compliance, and how fast your team ships new UI. This tutorial walks through building the same animated interface twice: once in React with Motion, once in Vue with GSAP, so you can see exactly where each library earns its keep.

Why React and Vue Take Different Paths to Animation in 2026

React and Vue solve UI reactivity in different ways, and that difference carries straight into animation. React re-renders components on state change and relies on a virtual DOM diff, so an animation library built for React needs to own the transition between renders itself. That is exactly what Motion does: its motion.div components intercept style changes and animate them outside React’s render cycle, which keeps 60fps interactions smooth even during heavy re-renders.

Vue takes a template-and-reactivity approach with fine-grained dependency tracking, and its ecosystem never converged on one dominant animation library the way React did around Framer Motion. Vue ships built-in <Transition> and <TransitionGroup> components for simple enter/leave states, but for anything beyond that, most production Vue teams reach for GSAP. GSAP does not care which framework renders the DOM node. It grabs a ref, tweens the properties you give it, and gets out of the way. That framework-agnostic design is why GSAP shows up in Vue, Svelte, and plain JavaScript projects alike, according to multiple 2026 comparison write-ups tracking its adoption.

The practical result: React developers default to Motion because it speaks React’s declarative language natively, with props like initial, animate, and exit that read like JSX. Vue developers lean on GSAP because it excels at the kind of scroll-driven, multi-element choreography that Vue’s built-in transitions were never designed to handle. Neither choice is locked in. Motion now ships Vue bindings, and GSAP works fine inside a React useEffect. But the defaults tell you where each library’s design center of gravity sits.

The history behind both libraries explains a lot of this split. GSAP has existed since 2008, long before React or Vue shipped a stable 1.0, and it was built as a general-purpose JavaScript tweening engine for banner ads and Flash-era interactive sites. It never assumed a component model because none existed yet, so it stayed framework-neutral by necessity, and that neutrality became an advantage once React and Vue both arrived years later. Framer Motion, by contrast, launched in 2018 specifically to solve animation inside React components, built by the team behind the Framer design tool. Its rename to Motion in early 2025 marked the first time the library formally reached outside React, which is the shift driving most of the 2026 comparison articles you will find when researching this topic.

Prerequisites: Versions and Tools You Need

Before you start, install the following. Version mismatches are the number one cause of animation bugs that “work on my machine,” so pin these exact versions if you are following along step by step.

Tool Version Used Here Release Date Notes
Node.js 24.x (Active LTS) June 2026 Node 22 remains in maintenance LTS if you cannot upgrade
npm 10.x (bundled with Node 24) – pnpm or Yarn work identically for this tutorial
Vite 8.1.3 July 2, 2026 Vite 8 uses the Rolldown bundler for faster cold starts
React 19.2.8 July 21, 2026 Latest stable release on the React 19 line
Vue 3.5.38 August 2026 Vue 3.6 is in beta; 3.5.x remains the production-recommended line
Motion (npm package “motion”) 13.1.1 2026 Formerly published as “framer-motion”; import from “motion/react”
GSAP 3.15.0 April 13, 2026 All plugins, including ScrollTrigger and Draggable, are now free

You will also need a code editor, a terminal, and a browser with dev tools open, since you will be checking frame rates in the Performance panel later. If you already have an existing React or Vue app, skip Step 1 and jump straight to the install commands in Steps 2 and 3.

Here is a realistic time budget for working through every step below, tested end to end on a mid-range laptop with a standard broadband connection. Total time runs close to two hours if you build both the React and Vue versions of every example, or under an hour if you focus on just one framework.

Step Task Time Estimate Difficulty
1-3 Scaffold projects, install Motion and GSAP 10 min Beginner
4-5 Build the first fade-in animation in both frameworks 15 min Beginner
6-7 AnimatePresence in React, ScrollTrigger in Vue 20 min Intermediate
8-9 Drag gestures and staggered timelines 20 min Intermediate
10 Add prefers-reduced-motion support 10 min Beginner
11-12 Performance profiling and test setup 15 min Intermediate
Complete project Assemble the animated product showcase page 25 min Intermediate

Step 1: Scaffold Your React and Vue Projects

Create two separate projects so you can compare them side by side. Open a terminal and run the following for the React side.

npm create vite@latest react-motion-demo -- --template react
cd react-motion-demo
npm install
npm run dev

Then, in a separate folder, scaffold the Vue project.

npm create vite@latest vue-gsap-demo -- --template vue
cd vue-gsap-demo
npm install
npm run dev

Both commands spin up a dev server on localhost, usually port 5173. Confirm each app loads the default Vite starter page before moving on. If either fails to start, check that Node reports version 24 with node -v, since Vite 8 drops support for older Node releases.

Step 2: Install Motion in Your React App

Inside the React project, install the Motion package. Note the package name: it is “motion,” not the old “framer-motion” name, though the legacy package still receives security patches for teams mid-migration.

npm install motion

If you inherited a codebase that already depends on “framer-motion,” you do not need to rip it out today. The old package still works, and Motion’s team maintains it for backward compatibility. New components, however, should import from motion/react going forward, since that is where new features and bug fixes land first.

Step 3: Install GSAP in Your Vue App

Switch to the Vue project and install GSAP the same way.

npm install gsap

Since GSAP 3.15, every plugin ships in the same package, so ScrollTrigger, Draggable, SplitText, and the rest install with that single command. Older tutorials that reference a separate “Club GreenSock” registry or a private npm token are out of date. You register plugins explicitly in code, which you will do in Step 7, but there is nothing extra to purchase or unlock.

Step 4: Build Your First Fade-In Animation in React With Motion

Create a new file called FadeCard.jsx inside src/. Motion’s core mental model is three props: initial describes the starting style, animate describes the end state, and transition controls timing.

import { motion } from "motion/react";

export default function FadeCard() {
  return (
    <motion.div
      className="card"
      initial={{ opacity: 0, y: 24 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.6, ease: "easeOut" }}
    >
      <h3>Motion in React</h3>
      <p>This card fades and slides into view on mount.</p>
    </motion.div>
  );
}

Import FadeCard into App.jsx and render it. Save the file, and the card should fade up from 24 pixels below its resting position over 600 milliseconds. Notice there is no ref, no useEffect, and no manual cleanup. Motion handles mount detection internally, which is the main reason React developers reach for it before GSAP: less boilerplate for the common 80% case of simple enter animations.

Step 5: Build the Same Fade-In Animation in Vue With GSAP

Now replicate that exact animation in Vue. Create FadeCard.vue in src/components/.

<template>
  <div ref="cardRef" class="card">
    <h3>GSAP in Vue</h3>
    <p>This card fades and slides into view on mount.</p>
  </div>
</template>

<script setup>
import { ref, onMounted } from "vue";
import gsap from "gsap";

const cardRef = ref(null);

onMounted(() => {
  gsap.from(cardRef.value, {
    opacity: 0,
    y: 24,
    duration: 0.6,
    ease: "power2.out",
  });
});
</script>

This is the syntax gap between the two libraries in miniature. Motion describes states declaratively as data (initial, animate), which fits naturally inside JSX. GSAP is imperative: you grab a DOM ref through onMounted, then tell gsap.from() exactly what to tween. Neither approach is wrong. Vue’s Composition API makes the ref-plus-lifecycle-hook pattern feel idiomatic, so most Vue developers do not experience GSAP as extra ceremony the way a React developer coming from Motion might.

Step 6: Layout Animations and AnimatePresence in React

Where Motion pulls ahead of GSAP inside React specifically is exit animations. Removing a DOM node before its animation finishes is a real problem: React unmounts a component the instant it disappears from JSX, before any CSS transition can play. Motion solves this with AnimatePresence, which delays the actual DOM removal until the exit animation completes.

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

function Modal({ isOpen, onClose }) {
  return (
    <AnimatePresence>
      {isOpen && (
        <motion.div
          className="overlay"
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          exit={{ opacity: 0 }}
          onClick={onClose}
        >
          <motion.div
            className="modal"
            initial={{ scale: 0.9, opacity: 0 }}
            animate={{ scale: 1, opacity: 1 }}
            exit={{ scale: 0.9, opacity: 0 }}
          >
            Modal content
          </motion.div>
        </motion.div>
      )}
    </AnimatePresence>
  );
}

Toggle isOpen from a parent component’s state, and both the overlay and modal will fade and scale out smoothly before React removes them from the tree. Building the equivalent by hand with plain CSS transitions and setTimeout calls to delay unmounting is a common source of bugs in older React codebases, and it is the single feature most cited by developers explaining why they picked Motion over rolling their own transitions.

Step 7: Scroll-Triggered Animations With GSAP ScrollTrigger in Vue

This is GSAP’s home turf. ScrollTrigger watches scroll position and fires animations when elements enter the viewport, and since it became free with GSAP 3.15, there is no reason to reach for a lighter-weight scroll library instead. In your Vue component, register the plugin once and reuse it across your app.

<script setup>
import { onMounted } from "vue";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";

gsap.registerPlugin(ScrollTrigger);

onMounted(() => {
  gsap.utils.toArray(".reveal").forEach((el) => {
    gsap.from(el, {
      opacity: 0,
      y: 60,
      duration: 0.8,
      scrollTrigger: {
        trigger: el,
        start: "top 85%",
      },
    });
  });
});
</script>

Add a class of reveal to any section you want to animate on scroll, and gsap.utils.toArray() picks them all up in one pass. The start: "top 85%" setting fires the animation once the element’s top edge crosses 85% down the viewport, which reads more naturally on mobile than a fixed pixel offset. Motion can do basic scroll-linked animation through its useScroll hook, but for pinned sections, scrubbing timelines, or horizontal scroll hijacking, GSAP’s ScrollTrigger remains the more capable tool regardless of which framework renders the markup.

Step 8: Gesture and Drag Interactions: Motion vs GSAP Draggable

Both libraries support draggable elements, but the ergonomics differ. In Motion, drag is a prop you add directly to a motion.div.

<motion.div
  className="card"
  drag
  dragConstraints={{ left: -100, right: 100 }}
  whileDrag={{ scale: 1.05 }}
  whileHover={{ scale: 1.02 }}
  whileTap={{ scale: 0.98 }}
/>

Five props give you constrained dragging, plus hover and tap micro-interactions, with zero manual pointer-event handling. In GSAP, the equivalent uses the Draggable plugin, which took over the free tier alongside ScrollTrigger in 2026.

import gsap from "gsap";
import { Draggable } from "gsap/Draggable";

gsap.registerPlugin(Draggable);

Draggable.create(".card", {
  type: "x",
  bounds: { minX: -100, maxX: 100 },
  onDrag: function () {
    gsap.to(this.target, { scale: 1.05, duration: 0.2 });
  },
});

GSAP’s Draggable exposes more granular control, including inertia, snapping to a grid, and multi-touch support, which matters for building things like a Kanban board or a custom carousel. Motion’s drag prop covers the common cases faster but hands you less control for edge cases like momentum-based flick gestures.

Step 9: Orchestrating Timelines and Staggered Reveals

Staggering, animating a list of items with a small delay between each one, is where both libraries show their design philosophy clearly. Motion uses variants and a parent-level staggerChildren transition.

const container = {
  hidden: {},
  show: { transition: { staggerChildren: 0.1 } },
};
const item = {
  hidden: { opacity: 0, y: 12 },
  show: { opacity: 1, y: 0 },
};

function ProductList({ items }) {
  return (
    <motion.ul variants={container} initial="hidden" animate="show">
      {items.map((it) => (
        <motion.li key={it.id} variants={item}>
          {it.label}
        </motion.li>
      ))}
    </motion.ul>
  );
}

GSAP builds the same effect with a timeline object and a stagger parameter, which also supports staggering from the center outward or in a random order, a feature Motion does not currently expose.

const tl = gsap.timeline();

tl.from(".list-item", {
  opacity: 0,
  y: 12,
  duration: 0.4,
  stagger: 0.1,
});

For sequencing multiple, unrelated animations, GSAP’s timeline API generally reads cleaner because you chain .to() and .from() calls in the order they should play, with position parameters like "-=0.2" to overlap them. Motion requires nesting variants or chaining separate animate() calls, which gets harder to follow past three or four steps.

Step 10: Respecting prefers-reduced-motion for Accessibility

Skipping this step is the fastest way to fail an accessibility audit. Users who enable “reduce motion” in their OS settings are telling you, explicitly, that large movements and parallax can trigger discomfort or vestibular symptoms. Motion has a built-in hook for this.

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

function FadeCard() {
  const shouldReduceMotion = useReducedMotion();

  return (
    <motion.div
      initial={{ opacity: 0, y: shouldReduceMotion ? 0 : 24 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: shouldReduceMotion ? 0.01 : 0.6 }}
    />
  );
}

GSAP has no equivalent built-in hook, so you read the media query yourself with the standard browser API and branch your tween values.

const prefersReducedMotion = window.matchMedia(
  "(prefers-reduced-motion: reduce)"
).matches;

gsap.from(cardRef.value, {
  opacity: 0,
  y: prefersReducedMotion ? 0 : 24,
  duration: prefersReducedMotion ? 0.01 : 0.6,
});

Wrap this check in a small utility function and reuse it across every component, in either framework. Treat it as a required line in every animation you ship, not an optional polish pass at the end of the project.

Step 11: Optimizing Bundle Size and Runtime Performance

Bundle size is where the two libraries diverge the most sharply. Motion’s core animation engine weighs roughly 17KB gzipped by independent benchmarks published in 2026, which is well under half of GSAP’s shipped size once you include commonly paired plugins like ScrollTrigger. That gap matters most on mobile connections and for teams optimizing Core Web Vitals, since a smaller JavaScript payload parses and executes faster on low-end devices.

GSAP earns that extra weight back with a hardware-accelerated tweening engine that many developers report holds steady frame rates even when animating dozens of elements in a single timeline, something CSS-transition-based approaches and even some JS libraries can struggle with under load. If your app animates a handful of cards and modals, Motion’s smaller footprint is the better trade. If you are building a marketing site with complex, choreographed scroll sequences, GSAP’s extra kilobytes buy real headroom.

Tree-shaking behaves differently between the two as well. Motion ships as a set of smaller, composable functions, so bundlers like Vite’s Rolldown-based pipeline can drop unused features fairly aggressively. GSAP’s core is more monolithic by design, since its internal tweening engine handles many property types in one pass, but individual plugins such as ScrollTrigger, Draggable, and SplitText import separately, so a project that only needs scroll reveals never pays for the drag or text-splitting code. Import plugins explicitly rather than through a bundled “all plugins” convenience import, and check your build output after every new plugin you add.

Factor Motion (React) GSAP (Vue-friendly)
npm package name motion gsap
Current version 13.1.1 3.15.0
GitHub stars (approx.) 33.4K 24.9K
Primary framework fit React-native, also ships Vue and JS bindings Framework-agnostic (React, Vue, Svelte, vanilla JS)
Core bundle size ~17KB gzipped Larger, but bundled with a hardware-accelerated tween engine
Best at Component-level UI transitions, layout animation, AnimatePresence Scroll storytelling, timelines, SVG morphing, complex sequencing
Built-in reduced-motion support Yes, via useReducedMotion() No, requires manual media query check
License and cost MIT, free Free since GSAP 3.15 (April 2026), including former paid plugins

Step 12: Testing, Debugging, and Shipping to Production

Before you ship, open Chrome DevTools, switch to the Performance panel, and record a few seconds while your animations run. Look for dropped frames in the FPS chart at the top of the recording. Both Motion and GSAP animate CSS transforms and opacity by default, which the browser compositor can handle off the main thread, so you should see a flat 60fps line under normal conditions. If you see jank, check whether you accidentally animate a layout-triggering property like width or top instead of transform.

For automated tests, avoid asserting on animation timing directly, since CI runners are slower and less consistent than your local machine. Instead, test the end state: assert that a modal’s aria-hidden attribute flips correctly, or that a component the animation library controls renders the expected content once the transition promise resolves. Both libraries expose completion callbacks, onAnimationComplete in Motion and onComplete in GSAP, which you can await in your test setup rather than adding arbitrary sleep calls.

Before deploying, also run a production build locally and load it over a throttled network profile in DevTools, set to “Slow 4G” or similar. Development builds of both React and Vue include extra warnings and checks that inflate load time, so testing against the actual production bundle gives you a realistic sense of how your animations feel on the connection speeds your real users have, not the fast local network your dev server runs on.

The Complete Project: An Animated Product Showcase Page

Bring the pieces together into one working page: a hero section that fades in on load, a staggered product grid, a scroll-revealed testimonials section, and a modal for product details. The file structure looks the same in both projects.

src/
  components/
    Hero.jsx        (or Hero.vue)
    ProductGrid.jsx
    Testimonials.jsx
    ProductModal.jsx
  App.jsx           (or App.vue)
  main.jsx          (or main.js)

In the React version, Hero.jsx reuses the fade-in pattern from Step 4, ProductGrid.jsx reuses the stagger pattern from Step 9, Testimonials.jsx could use Motion’s useScroll and useTransform hooks for a simple parallax, and ProductModal.jsx wraps the AnimatePresence pattern from Step 6. Wire them together in App.jsx with a single piece of state controlling which product’s modal is open.

In the Vue version, Hero.vue reuses the GSAP fade-in from Step 5, ProductGrid.vue reuses the timeline stagger from Step 9, Testimonials.vue reuses the ScrollTrigger pattern from Step 7, and ProductModal.vue uses a GSAP timeline that plays forward on open and reverses on close, since GSAP timelines support .reverse() natively without redefining the exit state.

<script setup>
import { ref } from "vue";
import gsap from "gsap";

const modalRef = ref(null);
let tl;

function openModal() {
  tl = gsap.timeline().to(modalRef.value, {
    opacity: 1,
    scale: 1,
    duration: 0.3,
  });
}

function closeModal() {
  if (tl) tl.reverse();
}
</script>

Run npm run build in each project and check the output bundle size report Vite prints in the terminal. This is the moment the numbers in the comparison table above stop being abstract: you will see your own app’s JavaScript payload reflect whichever library you picked, and you can decide from there whether the trade-off matches your project’s constraints.

Once both versions build cleanly, open each one in a browser side by side. Scroll through the testimonials section slowly and watch how each element enters. Click a product card to trigger the modal, then close it, paying attention to whether the exit animation feels abrupt or smooth. Drag a draggable card in both versions and compare how each handles the boundary when you release near the edge of its constraints. These small, hands-on comparisons tell you more about which library fits your product’s feel than any spec sheet, and they only take a few minutes once the code from the steps above is in place.

Common Pitfalls When Animating React and Vue Interfaces

  • Animating layout properties instead of transforms. Tweening width, height, top, or left forces the browser to recalculate layout on every frame. Animate transform and opacity instead, and let CSS handle sizing separately.
  • Forgetting to clean up GSAP instances in Vue. If a component unmounts while a GSAP tween or ScrollTrigger is still active, you can leak memory and trigger errors on elements that no longer exist. Call tween.kill() or ScrollTrigger.getAll().forEach(t => t.kill()) inside onUnmounted.
  • Mixing the old and new Motion import paths. Importing some components from “framer-motion” and others from “motion/react” in the same project can double your bundle size, since both packages ship separately. Pick one and migrate fully.
  • Skipping prefers-reduced-motion until the end of the project. Retrofitting accessibility into dozens of animated components takes far longer than building it in from Step 1, as shown above.
  • Animating on every re-render in React. If your initial and animate values depend on props that change frequently, Motion will replay the animation more often than you intend. Use the key prop deliberately to control when a component should be treated as newly mounted.
  • Registering GSAP plugins more than once. Calling gsap.registerPlugin() inside a component that mounts repeatedly (like a list item) can cause console warnings and wasted work. Register plugins once, at your app’s entry point.

Troubleshooting Guide for Motion and GSAP Issues

  • Animation does not play on first render. Confirm the component actually mounts after the state change. In React, check that the element is conditionally rendered rather than just hidden with CSS, since Motion needs a real mount event to trigger initial to animate.
  • GSAP tween runs once then stops responding. This usually means you created a new tween on every render or click without killing the previous one. Store the tween or timeline in a variable and reuse it.
  • AnimatePresence exit animation never fires. Each child inside AnimatePresence needs a stable, unique key prop. Without it, React treats the exiting element as if it never existed.
  • ScrollTrigger fires at the wrong scroll position after a layout change. Call ScrollTrigger.refresh() after any dynamic content load, image load, or font swap that changes page height.
  • Drag gesture feels laggy on mobile in Motion. Add dragElastic and confirm you are not also applying a CSS transition to the same element, since a conflicting CSS transition fights with Motion’s own transform updates.
  • Vue component’s GSAP animation runs before the DOM exists. Move the tween call from the component’s setup() body into onMounted(), since refs are null until after the first render.
  • Build size balloons after adding GSAP. Import only the plugins you actually use (for example, gsap/ScrollTrigger) rather than importing the entire package with wildcard imports.
  • Animations look fine locally but stutter in production. Check whether your production build still includes React or Vue’s development-mode warnings, which add overhead. Confirm NODE_ENV=production is set during the Vite build.
  • Reduced motion setting is ignored. Double check the media query string is exactly "(prefers-reduced-motion: reduce)" and that you read it at animation time, not just once at app startup, since users can toggle the OS setting while your app is open.

Advanced Tips for Production-Grade Animation Systems

Once the basics work, a few refinements separate a demo from a shippable animation system. First, centralize your easing curves and durations in a shared constants file instead of hardcoding numbers in every component. A design system with three or four approved easing curves reads as intentional. A codebase with forty slightly different durations reads as accidental.

Second, if your React app needs GSAP’s scroll or timeline strengths, you do not have to choose only one library. Wrap GSAP calls inside a small custom hook that handles setup in useEffect and teardown in the cleanup function, then use Motion for everything else. Several production teams run this hybrid setup deliberately: Motion for component transitions, GSAP for hero sections and marketing pages that need heavier choreography.

Third, profile on a mid-range Android device, not just your development laptop. Animation performance gaps between Motion and GSAP that are invisible on an M-series MacBook can show up clearly on a $200 phone, particularly during scroll-linked animations with many active ScrollTrigger instances. Throttle CPU in DevTools to 4x or 6x slowdown to approximate that experience before you ship.

Fourth, version-lock your animation dependencies more tightly than you would a typical utility library. Both Motion and GSAP occasionally change default easing curves or timing behavior between major versions, and an animation that looked correct in code review can shift subtly after an unpinned dependency update. Pin exact versions in your lockfile and review the changelog before bumping either library, especially ahead of a release your design team has already signed off on visually.

Finally, treat GSAP’s ScrollTrigger markers (markers: true) as a debugging tool you remove before deploying, and lean on Motion’s dev tools browser extension if you need to inspect animated values live. Both libraries ship developer-facing tooling that speeds up debugging far more than console.log statements sprinkled through animation callbacks.

Choosing Between Motion and GSAP: A Decision Framework

After building the same interface twice, the choice usually comes down to four questions rather than a blanket “React uses X, Vue uses Y” rule. First, what does your app mostly animate? If the answer is component-level state changes, modals, dropdowns, hover cards, list items entering and leaving, Motion’s declarative props match that job description closely, and its React-native design means less code for each interaction. If the answer is a marketing page, a portfolio site, or a product landing page with scroll-driven storytelling, GSAP’s ScrollTrigger and timeline system were purpose-built for exactly that.

Second, how much does bundle size matter to your specific audience? A B2B SaaS dashboard used mostly on desktop over broadband can absorb GSAP’s extra kilobytes without anyone noticing. A consumer app targeting emerging markets on 3G connections and budget Android phones benefits more from Motion’s lighter footprint, or from loading GSAP only on the specific pages that need it through code splitting.

Third, does your team already have GSAP experience from a previous project? Migrating an experienced GSAP team to Motion, or vice versa, costs real ramp-up time that a net-new project does not have to pay. Reusing existing expertise often outweighs a library’s theoretical fit for the task at hand, especially on a deadline.

Fourth, are you locked into one framework, or does your organization run both React and Vue across different products? Since GSAP behaves identically regardless of the framework rendering the DOM, teams maintaining both a React app and a Vue app can standardize on GSAP alone and reuse animation logic, easing curves, and internal training material across both codebases. That consistency argument is one of the strongest practical reasons larger organizations pick GSAP even for their React properties.

Frequently Asked Questions

Can I use Motion in a Vue project instead of GSAP?

Yes. Motion expanded beyond React and now ships Vue bindings alongside its vanilla JavaScript build. That said, most Vue teams still default to GSAP because the ecosystem’s existing tutorials, Nuxt integrations, and community components are built around it, so you will find more Vue-specific examples for GSAP than for Motion.

Is GSAP really free now, including ScrollTrigger and Draggable?

Yes. As of GSAP 3.15 in April 2026, every plugin that previously required a Club GreenSock membership, including ScrollTrigger, Draggable, and SplitText, ships free under the standard GSAP license. You install everything with a single npm install gsap command.

Do I need to migrate from framer-motion to the motion package?

Not urgently. The legacy “framer-motion” package still works and receives maintenance updates. New projects should start with “motion” and the motion/react import path, since that is where active development happens, but there is no forced deprecation timeline that requires an immediate rewrite of existing code.

Which library is faster, Motion or GSAP?

It depends on the animation type. Motion’s smaller bundle size means faster initial page load and parse time for typical UI transitions. GSAP’s tweening engine is built to hold steady frame rates when animating many elements simultaneously in complex timelines, which is a scenario Motion was not primarily designed around. Benchmark your specific use case rather than assuming one library wins universally.

Can I use GSAP inside React instead of Motion?

Yes, and some teams do exactly that for scroll-heavy marketing pages built in React, using useRef and useEffect the same way this tutorial used ref and onMounted in Vue. GSAP does not care which framework owns the DOM node it animates.

Does using an animation library hurt my Core Web Vitals score?

It can, if you import more of the library than you use or animate layout-triggering CSS properties instead of transforms. Both Motion and GSAP support tree-shaking and per-plugin imports, so import only what you need, animate transforms and opacity, and measure with Lighthouse or Chrome’s Performance panel after adding any new dependency.

What is the minimum GSAP or Motion setup for a simple fade-in, without learning the full API?

The code in Step 4 and Step 5 above covers it. In React, wrap the element in motion.div with initial and animate props. In Vue, grab a ref and call gsap.from() inside onMounted(). Both examples run in under ten lines of code and need no additional configuration.

Should a new project starting today pick Motion or GSAP by default?

For a pure React app focused on interactive UI, start with Motion, since its API integrates with component state without extra wiring. For a Vue app, a marketing site in either framework, or a project that needs to share animation logic across multiple frameworks, start with GSAP. Teams building both a React and a Vue product under one brand often standardize on GSAP for that cross-framework consistency alone, even though Motion would work fine for the React half.

Source: Tech Insider