GSAP (GreenSock Animation Platform) is a powerful animation library that works seamlessly with Vue.
Installation
bashnpm install gsap
Basic GSAP Animation
vue<script setup> import { ref, onMounted } from 'vue' import gsap from 'gsap' const boxRef = ref<HTMLElement | null>(null) onMounted(() => { if (boxRef.value) { gsap.to(boxRef.value, { x: 200, rotation: 360, duration: 1, ease: 'power2.out' }) } }) </script> <template> <div ref="boxRef" class="box">Animated!</div> </template>
GSAP with Transition Hooks
vue<script setup> import { ref } from 'vue' import gsap from 'gsap' const show = ref(true) function onEnter(el: HTMLElement, done: () => void) { gsap.from(el, { opacity: 0, y: -50, scale: 0.8, duration: 0.5, ease: 'back.out(1.7)', onComplete: done }) } function onLeave(el: HTMLElement, done: () => void) { gsap.to(el, { opacity: 0, y: 50, scale: 0.8, duration: 0.3, ease: 'power2.in', onComplete: done }) } </script> <template> <button @click="show = !show">Toggle</button> <Transition :css="false" @enter="onEnter" @leave="onLeave" > <div v-if="show" class="card">GSAP Animated Card</div> </Transition> </template>
Staggered Animations with GSAP
vue<script setup> import { ref } from 'vue' import gsap from 'gsap' const items = ref([1, 2, 3, 4, 5]) function onBeforeEnter(el: HTMLElement) { el.style.opacity = '0' el.style.transform = 'translateY(30px)' } function onEnter(el: HTMLElement, done: () => void) { const index = Number(el.dataset.index) gsap.to(el, { opacity: 1, y: 0, duration: 0.4, delay: index * 0.1, ease: 'power2.out', onComplete: done }) } function onLeave(el: HTMLElement, done: () => void) { const index = Number(el.dataset.index) gsap.to(el, { opacity: 0, y: -30, duration: 0.3, delay: index * 0.05, onComplete: done }) } </script> <template> <TransitionGroup :css="false" @before-enter="onBeforeEnter" @enter="onEnter" @leave="onLeave" > <div v-for="(item, index) in items" :key="item" :data-index="index" class="item" > Item {{ item }} </div> </TransitionGroup> </template>
GSAP Timeline
vue<script setup> import { ref, onMounted } from 'vue' import gsap from 'gsap' const containerRef = ref<HTMLElement | null>(null) onMounted(() => { const tl = gsap.timeline({ defaults: { duration: 0.5 } }) tl.from('.header', { y: -50, opacity: 0 }) .from('.content', { x: -100, opacity: 0 }, '-=0.2') .from('.button', { scale: 0, ease: 'back.out(2)' }) .from('.footer', { y: 50, opacity: 0 }, '-=0.3') }) </script>
Reactive Animations with watchEffect
vue<script setup> import { ref, watchEffect } from 'vue' import gsap from 'gsap' const progress = ref(0) const progressBar = ref<HTMLElement | null>(null) watchEffect(() => { if (progressBar.value) { gsap.to(progressBar.value, { width: `${progress.value}%`, duration: 0.5, ease: 'power2.out' }) } }) </script> <template> <input type="range" v-model.number="progress" min="0" max="100" /> <div class="progress-container"> <div ref="progressBar" class="progress-bar"></div> </div> </template>