| name | gsap-frameworks |
| description | Integrates GSAP into Vue 3, Nuxt 4, Svelte, and SvelteKit via onMounted/onMount, gsap.context scoped selectors, and ctx.revert() cleanup. Use when writing or reviewing GSAP in those non-React frameworks, including ScrollTrigger plugin registration. Not for React useGSAP/@gsap/react (gsap-web-animations) or GSAP tween/timeline recipes without a component lifecycle. |
| version | 1.0.1 |
GSAP with Vue, Svelte, and Other Frameworks
Production guide for integrating GSAP into Vue 3, Nuxt 4, Svelte, and other lifecycle-based component frameworks. Covers scoped selectors via gsap.context(), cleanup on unmount, plugin registration, and ScrollTrigger refresh patterns.
For React specifically, use the gsap-react skill (useGSAP hook, gsap.context()). This skill targets non-React frameworks.
When to Use
Apply this skill when:
- Writing or reviewing GSAP code in Vue 3 (Composition API or
<script setup>) or Nuxt 4.
- Writing or reviewing GSAP code in Svelte or SvelteKit.
- The user asks about GSAP with Vue, Svelte, Nuxt,
onMounted, onMount, onDestroy, or component lifecycle animation.
- Scoping GSAP selectors to a component root to avoid cross-component leakage.
- Setting up GSAP plugin registration (ScrollTrigger, SplitText, etc.) in a framework context.
- Cleaning up tweens and ScrollTriggers on component unmount/destroy.
Related skills:
- gsap-core — tweens, basic properties, easing.
- gsap-timeline — timeline construction and sequencing.
- gsap-scrolltrigger — scroll-driven animation, pinning, scrubbing.
- gsap-react — React-specific patterns (useGSAP, contextSafe).
Prerequisites
- GSAP installed in the project:
npm install gsap (or pnpm add gsap, yarn add gsap).
- For Vue: Vue 3.x with Composition API available.
- For Nuxt: Nuxt 4.x project with
composables/ directory support.
- For Svelte: Svelte 4.x or 5.x (lifecycle APIs differ slightly; see Svelte section).
- For ScrollTrigger or other plugins: import from
gsap/<PluginName> and register once at app level.
Windows host note (PowerShell): All CLI commands below assume PowerShell as the default shell. On macOS/Linux, commands are equivalent unless noted.
Procedure
Core Principles (All Frameworks)
- Create tweens and ScrollTriggers after the component's DOM is available (e.g.,
onMounted, onMount).
- Kill or revert them in the unmount (or equivalent) cleanup so nothing runs on detached nodes and there are no leaks.
- Scope selectors to the component root so
.box and similar only match elements inside that component, not the rest of the page.
Vue 3 (Composition API)
- Import
onMounted, onUnmounted, and ref from Vue.
- Import
gsap and any plugins (e.g., ScrollTrigger).
- Register plugins once at app level (e.g., in
main.js), not inside every component.
- In
onMounted, create a gsap.context() with the container ref as scope.
- In
onUnmounted, call ctx.revert().
import { onMounted, onUnmounted, ref } from "vue";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
export default {
setup() {
const container = ref(null);
let ctx;
onMounted(() => {
if (!container.value) return;
ctx = gsap.context(() => {
gsap.to(".box", { x: 100, duration: 0.6 });
gsap.from(".item", { autoAlpha: 0, y: 20, stagger: 0.1 });
}, container.value);
});
onUnmounted(() => {
ctx?.revert();
});
return { container };
},
};
Key points:
gsap.context(callback, scope) — pass container.value as the second argument so selectors like .item are scoped to that root.
- All animations and ScrollTriggers created inside the callback are tracked and reverted when
ctx.revert() is called.
- Always call
ctx.revert() in onUnmounted so tweens and ScrollTriggers are killed and inline styles reverted.
Vue 3 (<script setup>)
Same pattern with <script setup> syntax:
<script setup>
import { onMounted, onUnmounted, ref } from "vue";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
const container = ref(null);
let ctx;
onMounted(() => {
if (!container.value) return;
ctx = gsap.context(() => {
gsap.to(".box", { x: 100 });
gsap.from(".item", { autoAlpha: 0, stagger: 0.1 });
}, container.value);
});
onUnmounted(() => {
ctx?.revert();
});
</script>
<template>
<div ref="container">
<div class="box">Box</div>
<div class="item">Item</div>
</div>
</template>
Nuxt 4
- Create a reusable composable at
composables/useGSAP.ts to register GSAP plugins and provide lazy-loading for infrequently used plugins.
- Access
gsap, ScrollTrigger, and lazyLoadPlugin in components via useGSAP().
- Use
gsap.context(scope) and onUnmounted ctx.revert() in components, same as Vue 3.
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
const PLUGINS = [
"CSSRulePlugin", "CustomBounce", "CustomEase", "CustomWiggle",
"Draggable", "DrawSVGPlugin", "EaselPlugin", "EasePack", "Flip",
"GSDevTools", "InertiaPlugin", "MorphSVGPlugin", "MotionPathHelper",
"MotionPathPlugin", "Observer", "Physics2DPlugin", "PhysicsPropsPlugin",
"PixiPlugin", "ScrambleTextPlugin", "ScrollSmoother", "ScrollToPlugin",
"ScrollTrigger", "SplitText", "TextPlugin",
] as const;
const pluginMap = {
CustomEase: () => import("gsap/CustomEase"),
Draggable: () => import("gsap/Draggable"),
CSSRulePlugin: () => import("gsap/CSSRulePlugin"),
EaselPlugin: () => (),
: (),
: (),
: (),
: (),
: (),
: (),
: (),
: (),
: (),
: (),
: (),
: (),
: (),
: (),
: (),
: (),
: (),
: (),
: (),
: (),
} ;
= pluginMap;
= keyof ;
<K > = <<[K]>>;
<K > = <K>[K & keyof <K>];
() {
gsap.();
lazyLoadPlugin<K >(: K): <<K>> {
loader = pluginMap[plugin];
m = ();
p = (m )[plugin];
gsap.(p);
p;
}
{ gsap, , lazyLoadPlugin };
}
Access in components:
const { gsap, ScrollTrigger, lazyLoadPlugin } = useGSAP();
useGSAP() provides typed access to the gsap instance and lazy-load method.
- Lazy-load any plugin (SplitText, MorphSVG, etc.) that is not widely used to reduce initial bundle size.
- Use
gsap.context(scope) and onUnmounted ctx.revert() in components, same as Vue 3.
Svelte
- Import
onMount from Svelte.
- Import
gsap and any plugins.
- Use
bind:this={container} to get a reference to the root element.
- In
onMount, create a gsap.context() with the container as scope.
- Return a cleanup function from
onMount that calls ctx.revert().
<script>
import { onMount } from "svelte";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
let container;
onMount(() => {
if (!container) return;
const ctx = gsap.context(() => {
gsap.to(".box", { x: 100 });
gsap.from(".item", { autoAlpha: 0, stagger: 0.1 });
}, container);
return () => ctx.revert();
});
</script>
<div bind:this={container}>
<div class="box">Box</div>
<div class="item">Item</div>
</div>
bind:this={container} — get a reference to the root element to pass to gsap.context(scope).
return () => ctx.revert() — Svelte's onMount can return a cleanup function; ctx.revert() runs when the component is destroyed.
- Svelte 5 note: Svelte 5 uses a different lifecycle API (runes); the same principle applies: create in mounted and revert in destroyed.
Scoping Selectors
Always pass the scope (container element or ref) as the second argument to gsap.context(callback, scope):
gsap.context(() => { gsap.to(".box", ...) }, containerRef) — .box is only searched inside containerRef.
- Running
gsap.to(".box", ...) without a context scope in a component can affect other instances or the rest of the page.
ScrollTrigger Cleanup and Refresh
- ScrollTrigger instances are created when you use the
scrollTrigger config on a tween/timeline or ScrollTrigger.create().
- They are included in
gsap.context() and reverted when you call ctx.revert().
- Create ScrollTriggers inside the same
gsap.context() callback you use for tweens.
- Call
ScrollTrigger.refresh() after layout changes (e.g., after data loads) that affect trigger positions.
- In Vue: use
nextTick after DOM updates.
- In Svelte: use
tick after DOM updates.
- After async content load: call
ScrollTrigger.refresh() once content is rendered.
When to Create vs Kill
| Lifecycle | Action |
|---|
| Mounted | Create tweens and ScrollTriggers inside gsap.context(scope). |
| Unmount / Destroy | Call ctx.revert() so all animations and ScrollTriggers in that context are killed and inline styles reverted. |
Do not create GSAP animations in the component's setup or in a synchronous top-level script that runs before the root element exists. Wait for onMounted / onMount (or equivalent) so the container ref is in the DOM.
Pitfalls
- Creating tweens before mount: Do not create tweens or ScrollTriggers before the component is mounted (e.g., in
setup without onMounted); the DOM nodes may not exist yet.
- Ungscoped selectors: Do not use selector strings without a scope. Always pass the container to
gsap.context() as the second argument so selectors don't match elements outside the component.
- Skipping cleanup: Always call
ctx.revert() in onUnmounted / onMount's return so animations and ScrollTriggers are killed when the component is destroyed. Leaked tweens on detached nodes cause performance degradation and visual bugs.
- Registering plugins per render: Do not register plugins inside a component body that runs every render. It doesn't break anything but is wasteful. Register once at app level (e.g.,
main.js or a Nuxt plugin/composable).
- Forgetting ScrollTrigger.refresh(): After layout changes, image loads, font loads, or async data rendering, trigger positions may be stale. Call
ScrollTrigger.refresh() after the DOM updates.
- Animating pinned trigger elements in ways that invalidate measurements: Avoid animating layout properties (width, height, top, left) on pinned elements; this can cause ScrollTrigger measurement errors.
- Not respecting prefers-reduced-motion: Provide simpler transitions, instant states, or user-controlled playback for users with reduced-motion preference.
Verification
- Check that animations are scoped: Open browser DevTools Console and verify no GSAP inline styles appear on elements outside the component root after mount.
- Check cleanup on unmount: Navigate away from the component (or conditionally destroy it), then run in Console:
ScrollTrigger.getAll().length
The count should not include stale triggers from the unmounted component.
- Check for leaked tweens: After unmount, verify no console errors about tweening detached or null nodes.
- Check ScrollTrigger positions: After layout changes or data loads, run:
ScrollTrigger.refresh()
and verify trigger start/end positions update correctly.
- Check reduced-motion: In DevTools, emulate
prefers-reduced-motion: reduce (Rendering tab in Chrome DevTools) and verify animations degrade gracefully.
- Type check (Nuxt/TS): Run
npx vue-tsc --noEmit in PowerShell to verify the useGSAP composable types resolve correctly.
- Build check: Run
npm run build (or pnpm build) and confirm no GSAP-related import or tree-shaking errors.
Examples
Runnable Projects
- See
examples/vue/ for a runnable Vite + Vue 3 project demonstrating these patterns.
- See
examples/nuxt/ for a runnable Nuxt 4 project with plugin registration, lazy loading, and SSR-safe patterns.
When to load reference files: If the user needs a full project scaffold, read the files under examples/vue/ or examples/nuxt/ to provide copy-pasteable project structure. For plugin-specific API details, refer the user to the gsap-scrolltrigger or gsap-core skills.
Related Skills
- gsap-core — tweens, properties, easing fundamentals.
- gsap-timeline — timeline construction, sequencing, labels.
- gsap-scrolltrigger — scroll-driven animation, pinning, scrubbing, refresh patterns.
- gsap-react — React-specific patterns (useGSAP hook, contextSafe, cleanup).
References