Frameworks

GSAP in Vue

GSAP in Vue is the pattern for driving GSAP animations from a Vue 3 component: you create your tweens inside `onMounted` once the DOM exists, scope them to the component with a template ref, and kill them in `onUnmounted`. GSAP is framework-agnostic, so there's no Vue-specific build, you're just wiring the animation into Vue's lifecycle so it starts and cleans up at the right time.

Updated July 1, 2026

Mechanics

How GSAP runs inside a Vue component

There is no official Vue hook the way useGSAP exists for React. Vue's onMounted / onUnmounted lifecycle already gives you the two moments you need: run the animation after the element is in the DOM, and tear it down when the component leaves. Register any plugins once at the app level (in main.js), not inside the component.

Reach for a template ref instead of a global selector string. A ref points at the exact node this instance rendered, so two copies of the same component on one page never animate each other's elements.

RevealBlock.vue

When you're animating several children with one selector, wrap the work in gsap.context(callback, scope) and pass the container ref as the scope. Every tween and ScrollTrigger created inside the callback is tracked, so a single ctx.revert() in onUnmounted kills them all and restores inline styles.

StaggerList.vue

Vue's #2 spot is real

Vue is the second-most-used framework, with 44.8% of developers reaching for it against React's 69.9% (State of JS 2025). Component libraries mostly ship React-first, so wiring GSAP into Vue by hand is a common gap.
When

Use this pattern for

  • Entrance reveals on a component that mounts (onMounted + a template ref)
  • Staggered lists or grids where one selector targets many children (gsap.context scope)
  • ScrollTrigger-driven sections inside a Vue or Nuxt page, created and reverted in the same context
  • Hover microinteractions wired to @mouseenter / @mouseleave handlers that call gsap.to on a ref
Alternatives

Do it differently when

  • You're in React, not Vue, use the useGSAP hook from @gsap/react which handles the mount and cleanup for you
  • The animation is a simple one-shot on a single element, a bare gsap.from(ref.value, ...) with a tween.kill() in onUnmounted is lighter than pulling in gsap.context
  • Content loads async and shifts layout, call ScrollTrigger.refresh() after nextTick() so triggers recompute against the settled DOM
  • You need the value inside Vue reactivity (an animated counter bound to the template), animate a reactive object's property and read it in the template instead of touching the DOM node
In production

Used in these Annnimate components

Every Annnimate component ships a Vue build alongside the React and vanilla versions, and they all follow this shape: onMounted to build, template refs instead of selectors, onUnmounted to revert.

  • Text Reveal builds its line-by-line reveal timeline in onMounted and kills it in onUnmounted, scoped to the component root so multiple headings on a page stay independent
  • Magnetic Button wires gsap.quickTo follow tweens to the button ref inside the component's lifecycle, and reverts the context when the button unmounts so no pointer handler keeps firing on a detached node
Used in components

See it running in production

FAQ

Common questions

Is there a useGSAP hook for Vue?
No. useGSAP ships in the @gsap/react package and is React-only. In Vue you use the framework's own lifecycle: onMounted to create the animation and onUnmounted to revert it. gsap.context() gives you the scoping and batch-cleanup that useGSAP wraps up in React.
Should I use a template ref or a selector string in Vue?
Prefer a template ref for a single element, it points at exactly the node this instance rendered so two copies of the component never cross-animate. When one selector needs to hit many children (a staggered list), use gsap.context(callback, containerRef) so the selector is scoped to that container rather than the whole page.
Where do I register ScrollTrigger in a Vue app?
Once, at the app level, usually in main.js: import { ScrollTrigger } from 'gsap/ScrollTrigger' then gsap.registerPlugin(ScrollTrigger). Registering inside a component's setup runs on every render and is wasteful. In Nuxt, register in a client-only plugin so it never runs during SSR.
Why does my Vue animation run before the element exists?
You're creating the tween in setup or at the top of <script setup>, which runs before the DOM is mounted, so the ref is still null. Move the gsap call inside onMounted, and guard with if (!container.value) return before you touch it.
How do I clean up GSAP when a Vue component unmounts?
Call ctx.revert() in onUnmounted if you used gsap.context, or tween.kill() for a single tween. revert() kills every tween and ScrollTrigger created in that context and restores the inline styles GSAP set. Skipping this leaks ScrollTriggers and can leave handlers firing on detached nodes.