Building Smooth Scroll Experiences
Smooth scrolling has become a hallmark of premium web experiences. In this post, I'll walk through how I integrate Lenis with GSAP ScrollTrigger to create that buttery-smooth feel you see on Awwwards-winning sites.
Why Lenis?
Native browser scrolling is fine for most websites, but when you're building something that needs to feel crafted, you need more control. Lenis gives us:
- Consistent scroll behavior across browsers
- Smooth momentum-based scrolling
- Easy integration with animation libraries
- Touch device support
The Setup
First, install the dependencies:
npm install lenis gsap @gsap/react
The key is syncing Lenis with GSAP's ticker so ScrollTrigger animations stay perfectly in sync with the scroll position:
import { ReactLenis } from "lenis/react";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
function SmoothScroll({ children }) {
const lenisRef = useRef(null);
useEffect(() => {
function update(time) {
lenisRef.current?.lenis?.raf(time);
}
gsap.ticker.add(update);
gsap.ticker.lagSmoothing(0);
return () => gsap.ticker.remove(update);
}, []);
return (
<ReactLenis ref={lenisRef} root options={{ lerp: 0.08 }}>
{children}
</ReactLenis>
);
}
ScrollTrigger Animations
Once Lenis and GSAP are synced, you can create scroll-driven animations that feel natural:
gsap.to(".word", {
opacity: 1,
stagger: 0.1,
scrollTrigger: {
trigger: ".text-container",
start: "top 80%",
end: "bottom 40%",
scrub: 1,
},
});
The scrub: 1 parameter ties the animation directly to scroll position with a 1-second smoothing delay. This creates that satisfying feeling where content reveals as you scroll.
Performance Tips
- Use
will-changesparingly — only on elements that are actively animating - Prefer
transformandopacity— these properties are GPU-accelerated - Kill ScrollTriggers on unmount — memory leaks are real
- Use
once: truefor animations that should only play once
Smooth scrolling is one of those details that separates a good website from a great one. It's worth the extra setup.