Detect whether an element is in view
Phuoc Nguyen
Posted on December 10, 2023
In our previous post, we introduced the usePrevious()
hook, which helps us keep track of the previous value of a state. But did you know that this hook can also be used to detect when an element comes into view while scrolling? This is a powerful tool for creating engaging user experiences that respond to how users interact with your website.
When it comes to web development, detecting whether an element is in view can be incredibly useful. For example, you can use this technique to lazy-load images or videos, which greatly improves page performance by reducing the amount of data that needs to be loaded on page load. Additionally, you can use this technique for analytics tracking, such as tracking how far users scroll down a page or which sections of your website are getting the most attention.
But that's not all! You can also use this information to trigger animations. Imagine animating a section of your website when the user scrolls down and that section comes into view β it adds a dynamic and visually appealing aspect to your website.
In this post, we'll show you how to achieve this functionality using the usePrevious()
hook.
Checking if an element is visible while scrolling
If you're wondering whether an element on your webpage is visible while you're scrolling, you can use the getBoundingClientRect()
method. This method tells us about an element's size and position relative to the viewport.
To check if an element is visible, we compare the top and bottom edges of the element with the viewport's height. If the top edge is less than the viewport's height and the bottom edge is greater than 0, then we know the element is visible.
Here's a code snippet to help you out:
const rect = ele.getBoundingClientRect();
const isInView = rect.top < window.innerHeight &&
rect.bottom >= 0;
To get started, create a new reference for your element using the useRef()
method. This reference allows you to easily access and manipulate your element within your code.
const eleRef = React.useRef(null);
// Render
return (
<div ref={eleRef}>...</div>
);
We're creating a new state variable called isInView
to keep track of whether our element is currently visible on the screen. By default, it's set to false
.
const [isInView, setIsInView] = React.useState(false);
Next, we define a function called checkInView()
that checks whether our element is currently visible on the screen by getting its size and position using getBoundingClientRect()
. If it is visible, we set our isInView
state variable to true
. If not, we set it to false
.
const checkInView = () => {
const rect = eleRef.current.getBoundingClientRect();
setIsInView(
rect.top < window.innerHeight && rect.bottom >= 0
);
};
To initialize our isInView
state variable, we add an effect hook that calls checkInView()
once when our component mounts. And to ensure that our component is listening for the scroll
event, we add another effect hook that adds an event listener for the scroll
event and removes it when our component unmounts.
React.useEffect(() => {
checkInView();
}, []);
React.useEffect(() => {
document.addEventListener("scroll", checkInView);
return () => {
document.removeEventListener("scroll", checkInView);
};
}, []);
Now comes the interesting part. Remember the usePrevious()
hook we created in the previous post? We're going to use it now to retrieve the previous value of our isInView
state variable. Then, we'll add another effect hook that checks whether our element has just come into view by comparing the current value of isInView
with the previous value. If it has, we can do something cool with the element.
const wasInView = usePrevious(isInView);
React.useEffect(() => {
if (!wasInView && isInView) {
// Element has come into view
// Do something with the element ...
console.log("Element is in view");
}
}, [isInView]);
With this technique, you can easily detect when an element comes into view while scrolling and take additional actions accordingly. Exciting, right? Let's dive into the next section to see how we can apply this technique to a real-life use case.
Good to know
Apart from handling the
scroll
event, there are other ways to check if an element is in view, like using the Intersection Observer API. We'll cover that approach in another series, so stay tuned!
Triggering animations when an element appears on screen
Let's say you have a website showcasing different types of products, each represented by a card with an image and some information. To make the site more engaging, you want to add an animation that fades in and scales the product when the user scrolls to the corresponding card.
To achieve this, you can modify the code example above. Instead of a console.log
statement, you can add your animation function to be triggered when the element comes into view.
Here's an example: we add the CSS class card__animated
to each card when it becomes visible.
React.useEffect(() => {
if (!wasInView && isInView) {
eleRef.current.add('card__animated');
}
}, [isInView]);
At first, each card on the page is given the card
class. This class is used to style the card element, which usually includes a product image and some information. Initially, the card is invisible with an opacity of 0. To improve performance during animation, the will-change
property is used to let the browser know that the transform
and opacity
properties will change.
To prepare for animation, the transform
property is used to move the card offscreen by 4rem (about two-thirds of its height) and scale it down to 80% of its size. This creates space for the card to be animated back into view later.
Finally, the transition
property is used to animate any changes to the transform
and opacity
properties over a period of 400ms (0.4 seconds).
This is how we style the card
class:
.card {
opacity: 0;
will-change: transform, opacity;
transform: translateY(4rem) scale(0.8);
transition: all 400ms;
}
To trigger our animation, we add the .card__animated
class to our card element. This class does two things: it sets the opacity of our card to 1 and scales it up to its original size, all while transitioning smoothly onto the screen with the translateY(0)
function.
The animation increases the card's opacity and smoothly moves it from offscreen to its final position on the page.
This is what its declarations look like:
.card__animated {
opacity: 1;
transform: translateY(0) scale(1);
}
By adding this animation, we can create a more engaging user experience that grabs the attention of our customers and encourages them to interact with our website.
Demo
Check out the final demo below! It includes 40 cards, each representing a different product. For demonstration purposes, we are only displaying the index of each product.
Conclusion
Detecting when an element is in view while scrolling can greatly improve your website's user experience. Not only does it make your site load faster by reducing the amount of data that needs to load at once, but it also lets you track user behavior and create cool animations based on how users interact with your site.
With the usePrevious()
hook and getBoundingClientRect()
method, it's easy to check if an element is visible while scrolling and take action accordingly. Whether you're loading images as users scroll or triggering animations, this technique adds a dynamic and visually appealing aspect to your website.
So why not give it a try? Experiment with different use cases and see how you can make your website stand out with this powerful tool.
It's highly recommended that you visit the original post to play with the interactive demos.
If you found this series helpful, please consider giving the repository a star on GitHub or sharing the post on your favorite social networks π. Your support would mean a lot to me!
If you want more helpful content like this, feel free to follow me:
Posted on December 10, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.