Email

Animate.css in your react project

We will cover how to add animations to your react project with animate.css

Install animate.css to your project

npm i animate.css

Then we need to paste the following code as a component:

"use client"

import React, { useRef, useEffect, useState } from "react"

type TAnimations = {
  name?: string
  children: React.ReactNode
}

const Animation = ({ name = "fadeIn", children }: TAnimations) => {
  const ref = useRef<HTMLDivElement>(null)
  const [hasAnimated, setHasAnimated] = useState(false)
  const [hasPageLoaded, setHasPageLoaded] = useState(false)

  useEffect(() => {
    // Set the page load flag once the page has loaded
    const handlePageLoad = () => {
      setHasPageLoaded(true)
    }

    if (document.readyState === "complete") {
      // If the page is already loaded
      handlePageLoad()
    } else {
      // Otherwise, wait for the page to load
      window.addEventListener("load", handlePageLoad)
    }

    return () => {
      window.removeEventListener("load", handlePageLoad)
    }
  }, [])

  useEffect(() => {
    if (!hasPageLoaded || hasAnimated) return

    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setHasAnimated(true) // Mark animation as applied
        }
      },
      {
        threshold: 0.1, // Trigger when at least 10% of the element is visible
      }
    )

    if (ref.current) {
      observer.observe(ref.current)
    }

    return () => {
      if (ref.current) {
        observer.unobserve(ref.current)
      }
    }
  }, [hasPageLoaded, hasAnimated])

  return (
    <div
      ref={ref}
      className={`${
        hasAnimated ? `animate__animated animate__${name}` : "opacity-0"
      }`}
    >
      {children}
    </div>
  )
}

export default Animation

We will then pass in a component we want to animate, example below

import Animation from "@/where/ever/that/component/is/located"

const AnimatedSection = () => {
  return (
    <section className="some-section-or-other">
      <Animation><h1>Hello world!</h1></Animation
    </section>
  )
}

export default AnimatedSection

What is happening under the hood

"use client" Directive

  • Ensures the component runs on the client side in Next.js, since it relies on browser APIs like window and document.

Imports & Type Definitions

  • Imports necessary React hooks (useRef, useEffect, useState).

  • Defines a TypeScript type (TAnimations) that specifies the props:

    • name: Type of animation (default: "fadeIn").

    • children: The content inside the animated wrapper.

Setting Up State & References

  • useRef<HTMLDivElement>(null): Creates a reference to the component’s container to track its visibility.

  • hasAnimated: A state variable to check if the animation has already played.

  • hasPageLoaded: A state variable that ensures animations don’t run until the page has fully loaded.

Handling Page Load (useEffect)

  • Detects if the page is already loaded or waits for the load event.

  • Prevents animations from triggering too early when the page hasn't fully rendered.

Observing When the Component is Visible (useEffect)

  • Uses the Intersection Observer API to check when the component enters the viewport.

  • If at least 10% of the element is visible, it triggers the animation and stops observing.

Rendering the Animated Element

  • Wraps the children in a <div> that:

    • Starts with opacity-0 (hidden).

    • Applies the animation class (animate__animated animate__${name}) when it becomes visible.

Get in touch

I am always free to discuss new projects, opportunities or any assistance you may require.

Responses usually take less than 24 hours.