Hello Guys In this tutorial, we’ll unravel the secrets behind creating captivating on-scroll effects that seamlessly elevate the user experience. One popular technique is the scroll-reveal animation, where elements come into view as the user scrolls down the page, today we’ll explore how to implement such animations using Intersection Observer in a Next.js application.
Begin by setting up your Next.js project.
npx create-next-app@latest
In src/components let’s create the RevealComp
component encapsulates the logic for triggering animations when elements enter/exit the viewport. Let's break down its key features:
Props:
children
: The content to be revealed.threshold
: The percentage of the element that must be visible to trigger the animation.duration
: The duration of the animation.x
and y
: Optional parameters for horizontal and vertical translation.Code:
// src/components/reveal.tsx
import React, { useEffect, useRef, useState } from 'react';
const RevealComp = ({ children, threshold, duration, x, y }) => {
x = x || 0
y = y || 0
const ref = useRef(null)
const [intersecting, setIntersecting] = useState(false)
};
export default RevealComp;
x
and y
are set to default values of 0 if not provided.ref
is initialized using useRef
to reference the DOM element.intersecting
state is set to false
initially using useState
to track whether the element is intersecting the viewport.Code:
...
useEffect(() => {
if (ref.current) {
const intersectionObserver = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
setIntersecting(true)
} else {
setIntersecting(false)
}
}, {
threshold
})
intersectionObserver.observe(ref.current)
return () => {
if (ref.current) {
intersectionObserver.unobserve(ref.current)
}
}
}
}, [])
...
useEffect
is used to set up and clean up the Intersection Observer.ref
element and updates the intersecting
state based on whether the observed element is intersecting with the viewport.threshold
prop is used to specify the percentage of the target element's visibility needed to trigger the intersection.Code:
...
return (
<div
style={
{
transitionDuration: duration,
transform:!intersecting ? `translate(${x}px, ${y}px)` : "translate(0px, 0px)"
}
}
className={`transition ${intersecting ? "opacity-100" : "opacity-0"}`} ref={ref}>
{children}
</div>
)
...
<div>
element with dynamic styles based on the intersecting
state.transform
property is used to apply translation based on the x
and y
values if we need element to slide from left to right top to bottom or vice versa.Now in our home page.tsx
component we can use RevealComp
to create scroll-reveal animations. For demo, we have two sections with images and text, each revealing/hiding as the user scrolls.
// src/app/page.tsx
import RevealComp from '@/components/reveal'
import Image from 'next/image'
import React, { useEffect, useRef, useState } from 'react'
export default function Home() {
return (
<div className='container px-6 max-w-4xl overflow-x-hidden mx-auto'>
<h1 className='text-4xl font-bold mt-10'>ONScroll Animation</h1>
<div className='grid grid-cols-2 gap-10 md:grid-cols-2 min-h-[70vh] items-center'>
<div className='md:order-2'>
<RevealComp duration='300ms' threshold={1}>
<div className='relative w-full max-w-sm h-52 rounded overflow-hidden'>
<Image className='object-cover' fill src={"https://picsum.photos/seed//500/500"} alt='hero-image' ></Image>
</div>
</RevealComp>
</div>
<div className='md:order-1'>
<RevealComp y={-20} duration='300ms' threshold={0.9}>
<h2 className='text-xl md:text-4xl mb-4 font-bold'>Hello,World</h2>
<p className='max-w-sm text-sm'>Lorem ipsum dolor sit amet consectetur adipisicing elit. Nulla qui provident dolor beatae laborum, nisi laudantium tempora numquam aut molestiae velit eius minus. Odio voluptas at eveniet quasi, excepturi eaque?</p>
</RevealComp>
</div>
</div>
<div className='grid gap-10 grid-cols-2 mt-20 md:grid-cols-2 min-h-[50vh] items-center'>
<RevealComp x={-10} duration='300ms' threshold={0.75}>
<div className='relative w-full max-w-sm h-52 rounded overflow-hidden'>
<Image className='object-cover' fill src={"https://picsum.photos/seed/r2/500/500"} alt='hero-image' ></Image>
</div>
</RevealComp>
<div className='self-center'>
<RevealComp x={20} duration='200ms' threshold={0.75}>
<h2 className='text-xl md:text-4xl mb-4 font-bold'>Welcome</h2>
<p className='max-w-sm text-sm'>Lorem ipsum dolor sit amet consectetur adipisicing elit. Nulla qui provident dolor beatae laborum, nisi laudantium tempora numquam aut molestiae velit eius minus. Odio voluptas at eveniet quasi, excepturi eaque?</p>
</RevealComp>
</div>
</div>
</div>
)
}
The component returns a JSX structure containing a container with a specified maximum width, preventing horizontal overflow. Two grid layouts are created. The first grid has two columns, and the second grid has two columns with a larger top margin. Both grids use the RevealComp
component for scroll-based animations. The RevealComp
component is used with specified duration and threshold props. This encapsulates the content within the component for scroll-based animations. Similar structures are repeated with text content and images, each wrapped in the RevealComp
for scroll-based animations.
Now you can run the Next JS app using npm run dev
Visit http://localhost:3000
in your browser to see the animation in action.
Congratulations! You’ve successfully implemented scroll-reveal animations in a Next.js application using Intersection Observer. This fundamental technique will help you in improving the visual appeal of your website, providing a more dynamic and engaging user experience. Feel free to experiment further, tweak the parameters, and integrate these techniques into your own projects. Happy coding!