Composables
useScrollTrigger()
Scroll-driven animations with GSAP ScrollTrigger.
Setup
Enable the plugin in nuxt.config.ts:
nuxt.config.ts
export default defineNuxtConfig({
gsap: {
plugins: ['ScrollTrigger'],
},
})
Basic usage
The simplest way: pass scrollTrigger directly inside any gsap.to/from call.
components/FadeIn.vue
<script setup lang="ts">
const boxRef = ref<HTMLElement | null>(null)
onMounted(() => {
gsap.from(boxRef.value, {
opacity: 0,
y: 40,
duration: 0.8,
scrollTrigger: boxRef.value,
})
})
</script>
<template>
<div ref="boxRef">Scroll to reveal me</div>
</template>
For more control over start/end positions and cleanup:
components/ScrollSection.vue
<script setup lang="ts">
const ScrollTrigger = useScrollTrigger()
const sectionRef = ref<HTMLElement | null>(null)
onMounted(() => {
if (!sectionRef.value) return
gsap.from(sectionRef.value, {
opacity: 0,
y: 60,
duration: 1,
scrollTrigger: {
trigger: sectionRef.value,
start: 'top 80%',
end: 'top 40%',
scrub: true,
},
})
})
onUnmounted(() => {
ScrollTrigger.getAll().forEach(t => t.kill())
})
</script>
<template>
<section ref="sectionRef">
<h2>Scroll to reveal</h2>
</section>
</template>
Using with gsap.context()
The context form of useGsap() automatically reverts all ScrollTrigger instances it creates:
const containerRef = ref<HTMLElement | null>(null)
useGsap(() => {
gsap.from('.card', {
opacity: 0,
y: 40,
stagger: 0.1,
scrollTrigger: {
trigger: '.card',
start: 'top 85%',
},
})
}, { scope: containerRef })
Pinning
onMounted(() => {
ScrollTrigger.create({
trigger: sectionRef.value,
pin: true,
start: 'top top',
end: '+=500',
})
})
Refreshing
Call ScrollTrigger.refresh() after dynamic content changes (e.g. image load, route change):
onMounted(async () => {
await nextTick()
ScrollTrigger.refresh()
})
ScrollSmoother requires ScrollTrigger to also be listed in plugins.