How to fade in content as it scrolls into view
Tags: react, javascript, css, webdev
Published: 2019-08-29 20:00:51

---
title: How to fade in content as it scrolls into view
published: true
description: Want to make your content fade in as it scrolls into view? This article will give you the how-to!
tags: react, javascript, css, webdev
cover_image: https://images.unsplash.com/photo-1472805911884-dc4c5797ee37?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1440&q=80
canonical_url: https://www.selbekk.io/blog/2019/08/how-to-fade-in-content-as-it-scrolls-into-view/
---

Today, I want to show you a technique for displaying content in a nice and nifty way - by fading it in as it shows up!

## The fady slidy part 🎚

Let's start with specifying the CSS required. We create two classes - a `fade-in-section` base class, and a `is-visible` modifier class. You can - of course - name them exactly what you want.

The `fade-in-section` class should hide our component, while the `is-visible` class should show it. We'll use CSS transitions to translate between them. 

The code looks like this:

```css
.fade-in-section {
  opacity: 0;
  transform: translateY(20vh);
  visibility: hidden;
  transition: opacity 0.6s ease-out, transform 1.2s ease-out;
  will-change: opacity, visibility;
}
.fade-in-section.is-visible {
  opacity: 1;
  transform: none;
  visibility: visible;
}
```

Here, we use the `transform` property to initially move our container down 1/5th of the viewport (or 20 viewport height units). We also specify an initial opacity of 0.

By transitioning these two properties, we'll get the effect we're after. We're also transitioning the `visibility` property from `hidden` to `visible`.

Here's the effect in action:

{% codesandbox festive-gould-exvw7 %}

Looks cool right? Now, how cool would it be if we had this effect whenever we scroll a new content block into the viewport?

## The showy uppy part 👋

Wouldn't it be nice if an event was triggered when your content was visible? We're going to use the `IntersectionObserver` DOM API to implement that behavior.

The `IntersectionObserver` API is a really powerful tool for tracking whether something is on-screen, either in part or in full. If you want to dig deep, I suggest you read this [MDN article](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) on the subject.

Quickly summarized, however, an intersection observer accepts a DOM node, and calls a callback function whenever it enters (or exits) the viewport. It gives us some positional data, as well as nice-to-have properties like `isIntersecting`, which tell us whether something is visible or not.

We're not digging too deep into the other cool stuff you can do with intersection observers in this article though, we're just implementing a nice "fade in on entry"-feature. And since we're using React, we can write a nice reusable component that we can re-use across our application.

Here's the code for implementing our component:

```js
function FadeInSection(props) {
  const [isVisible, setVisible] = React.useState(true);
  const domRef = React.useRef();
  React.useEffect(() => {
    const observer = new IntersectionObserver(entries => {
      entries.forEach(entry => setVisible(entry.isIntersecting));
    });
    observer.observe(domRef.current);
    return () => observer.unobserve(domRef.current);
  }, []);
  return (
    <div
      className={`fade-in-section ${isVisible ? 'is-visible' : ''}`}
      ref={domRef}
    >
      {props.children}
    </div>
  );
}
```

And here's a sandbox implementing it:

{% codesandbox beautiful-wiles-k23w5 %}

If you're looking for a copy and paste solution - here you go.

### What's happening - step by step

If you want to understand what's happening, I've written a step-by-step guide below, that explains what happens.

First, we call three built in React Hooks - `useState`, `useRef` and `useEffect`. You can read more about each of these hooks in [the documentation](https://reactjs.org/docs/hooks-reference.html#basic-hooks), but in our code we're doing the following:

1. Create a state variable indicating whether the section is visible or not with `useState`. We default it to `false`
2. Create a reference to a DOM node with `useRef`
3. Create the intersection observer and starting to observe with `useEffect`

The setup of the intersection observer might look a bit unfamiliar, but it's pretty simple once you understand what's going on.

First, we create a new instance of the IntersectionObserver class. We pass in a callback function, which will be called every time any DOM element registered to this observer changes its "status" (i.e. whenever you scroll, zoom or new stuff comes on screen). Then, we tell the observer instance to observe our DOM node with `observer.observe(domRef.current)`.

Before we're done, however, we need to clean up a bit - we need to remove the intersection listener from our DOM node whenever we unmount it! Luckily, we can return a cleanup function from `useEffect`, which will do this for us.

That's what we're doing at the end of our `useEffect` implementation - we return a function that calls the `unobserve` method of our observer. (Thanks to [Sung Kim](https://dev.to/dance2die) for pointing this out to me in the comment section!)

The callback we pass into our observer is called with a list of entry objects - one for each time the `observer.observe` method is called. Since we're only calling it once, we can assume the list will only ever contain a single element.

We update the `isVisible` state variable by calling its setter - the `setVisible` function - with the value of `entry.isIntersecting`. We can further optimize this by only calling it once - so as to not re-hide stuff we've already seen.

We finish off our code by attaching our DOM ref to the actual DOM - by passing it as the `ref` prop to our `<div />`.

We can then use our new component like this:

```jsx
<FadeInSection>
  <h1>This will fade in</h1>
</FadeInSection>

<FadeInSection>
  <p>This will fade in too!</p>
</FadeInSection>

<FadeInSection>
  <img src="yoda.png" alt="fade in, this will" />
</FadeInSection>
```

And that's how you make content fade in as you scroll into the view!

I'd love to see how you achieve the same effect in different ways - or if there's any way to optimize the code I've written - in the comments.

Thanks for reading!

## A final note on accessibility

Although animation might look cool, some people have physical issues with them. In their case, animations is detrimental to the user experience. Luckily, there's a special media query you can implement for those users - namely `prefers-reduced-motion`. You can (and should!) read more about it in [this CSS Tricks article](https://css-tricks.com/revisiting-prefers-reduced-motion-the-reduced-motion-media-query/) on the subject.