Introducing PrimeReact v11-alpha 🎉Discover Now

useAnimateOnScroll

Hook that applies enter and leave CSS animations to elements based on viewport intersection.

Scroll Down
Discover real-world design inspiration.
Featuring over 400,000 screens and 1,000 iOS, Android & Web apps.
basic-demo

Usage#

import { useAnimateOnScroll } from '@primereact/headless/animateonscroll';
const { rootProps } = useAnimateOnScroll({ enterClassName: 'fade-in' });
 
return <div {...rootProps}></div>;

useAnimateOnScroll wires an Intersection Observer to a single element and toggles CSS animation classes based on viewport visibility. See Primitive for a component-based API.

Features#

  • Viewport-driven animation — applies an enter class when the element scrolls in and a leave class when it scrolls out
  • Intersection control — pass root, rootMargin, and threshold to tune when the observer fires
  • Single-shot mode — once disconnects the observer after the first entry so the animation never repeats
  • Automatic class cleanup — animation classes are removed on animationend and transitionend to leave a clean DOM
  • Data-attribute hooks — data-enter and data-leave flip on the root during each phase for CSS targeting

Working with callbacks#

Pair enter and leave classes#

Combine enterClassName with a matching leaveClassName when you need bidirectional motion tied to scroll position.

const { rootProps } = useAnimateOnScroll({
    enterClassName: 'slide-in',
    leaveClassName: 'fade-out'
});

Fire the animation only once#

Set once when the element should animate in on first view and then stay in its final state even as the user scrolls past it.

const { rootProps } = useAnimateOnScroll({ enterClassName: 'fade-in', once: true });

Tune the trigger point#

Use threshold and rootMargin to require more of the element to be visible before the animation starts, which is useful for larger hero sections.

const { rootProps } = useAnimateOnScroll({
    enterClassName: 'fade-in',
    threshold: 0.8,
    rootMargin: '0px 0px -100px 0px'
});

Scope intersection to a scroll container#

Pass an element as root to observe intersection inside a scrollable panel rather than the viewport.

const scrollRef = React.useRef<HTMLDivElement>(null);
 
const { rootProps } = useAnimateOnScroll({
    enterClassName: 'fade-in',
    root: scrollRef.current
});

Styling with data attributes#

The root element carries data-scope="animateonscroll" and data-part="root". During each animation phase, data-enter or data-leave is set so you can target mid-animation state from CSS.

[data-scope='animateonscroll'][data-enter] {
    will-change: opacity, transform;
}
 
[data-scope='animateonscroll'][data-leave] {
    pointer-events: none;
}

API#

useAnimateOnScroll#

NameTypeDefault
enterClassNamestring—
CSS class names that are applied when the element enters the viewport.
leaveClassNamestring—
CSS class names that are applied when the element leaves the viewport.
oncebooleanfalse
When enabled, animation is triggered only once.

Accessibility#

No keyboard behavior — animations trigger based on viewport visibility only. See Primitive for full WAI-ARIA compliance details.