Hybrid Astro UI

AnimateScroll

Open in ChatGPT

A lightweight scroll-triggered animation wrapper that automatically animates each of its direct children as they enter or leave the viewport. Supports nested usage for granular control and configurable visibility thresholds

Gallery

example-imageexample-imageexample-imageexample-image

Landscape Description

A soft wind drifts across the valley, brushing through tall grass that bends like waves beneath a slow morning sun. In the distance, mountains rise in layered shades of blue, their peaks still wrapped in thin veils of mist. A narrow river cuts through the landscape, catching the light and scattering it in silver ripples. Clusters of wildflowers dot the open fields, their colors flickering gently as the breeze moves past them. Above, the sky stretches wide and calm, painted with long strokes of pale gold and quiet clouds drifting lazily across the horizon. The whole scene feels suspended in a peaceful stillness, as if the world were taking a quiet breath before the day truly begins.

example-imageexample-imageexample-imageexample-imageexample-imageexample-imageexample-image
pnpm dlx hybrid-astro-ui@latest add animate-scroll
npx hybrid-astro-ui@latest add animate-scroll
yarn dlx hybrid-astro-ui@latest add animate-scroll
bunx hybrid-astro-ui@latest add animate-scroll

Usage

The AnimateScroll component automatically applies entrance and exit animations to each of its direct children, triggering the effect only when an element enters or leaves the visible viewport area. This design enables clean, scalable, and fully decoupled animations without the need for extra classes or manual logic.

If you need more granular control—for example, animating internal sections, specific groups, or individual blocks within the same block—you can simply nest additional AnimateScroll components. Each instance manages its own set of children, allowing you to create independent transitions inside a shared layout.

The component also accepts a threshold property, which defines the percentage of the element that must be visible in the viewport before the animation is triggered. Lower values (e.g., 0.1) cause the animation to start earlier, even when only a small portion of the element is visible. Higher values (e.g., 0.5 or 0.8) delay the animation until a larger part of the element appears, creating smoother and more controlled visual effects.

Complex layout

The following example demonstrates a more complex layout where granular animation is applied both to main layout sections and to inner blocks. In this setup, the outer AnimateScroll> component animates only its direct children, such as the header and the gallery images.

To animate internal sections independently, you can simply nest another AnimateScroll inside the layout. This allows specific content blocks—like the description section with its heading and paragraph—to control their own animation without being affected by the parent component.

This modular approach provides precise control over how each group of blocks behaves within complex interfaces, while keeping the API clean and avoiding the need for additional classes or duplicated logic. You can further fine-tune the animation behavior using the threshold property, which determines the percentage of visibility required for an element to start animating. Higher values produce smoother, later transitions, while lower values trigger the animation earlier.

---
import { AnimateScroll } from "@/src/components/hybrid-astro-ui/animate-scroll"
---
<AnimateScroll 
    threshold={0.5}
    class="grid grid-cols-3 gap-3 border rounded-xl p-4 place-items-center">

        <h2  class="col-span-2">Gallery</h2>

        { [landg_1, landg_2, landg_3,landg_1].
            map(image =>  
                <Image width={300} 
                src={image} class="m-0!" 
                alt="example-image"/>) 
        }

    <AnimateScroll class="col-span-2">
        <h2  >Landscape Description</h2>
        <p class="line-clamp-7 md:line-clamp-none">A soft wind drifts across the valley, brushing through tall grass that bends like waves beneath a slow morning sun. In the distance, mountains rise in layered shades of blue, their peaks still wrapped in thin veils of mist. A narrow river cuts through the landscape, catching the light and scattering it in silver ripples. Clusters of wildflowers dot the open fields, their colors flickering gently as the breeze moves past them. Above, the sky stretches wide and calm, painted with long strokes of pale gold and quiet clouds drifting lazily across the horizon. The whole scene feels suspended in a peaceful stillness, as if the world were taking a quiet breath before the day truly begins.</p>
    </AnimateScroll>

    { 
        [landg_3, landg_2, landg_3,landg_1, landg_3, landg_2, landg_3].
            map(image =>  
                <Image width={300} 
                src={image} 
                class="m-0!" 
                alt="example-image"/>) 
    }
</AnimateScroll>

Simple layout

This example demonstrates a basic usage of the AnimateScroll component where only text-based content is animated. The component applies scroll-triggered animations exclusively to its direct children, which in this case include the main heading and each generated text block.

By wrapping the repetitive content inside AnimateScroll, every section becomes individually animated as it enters the viewport. This provides a clean and minimal setup without requiring additional classes or animation logic. The threshold property is set to 0.5, meaning that each element must be at least 50% visible before its animation is triggered, resulting in smoother and more intentional transitions.

This layout is ideal for simple documentation sections, article previews, or any scenario where vertical text blocks should animate naturally as the user scrolls.

Example containing only text, simple animation

Subtitle

A soft wind drifts across the valley, brushing through tall grass that bends like waves beneath a slow morning sun. In the distance, mountains rise in layered shades of blue, their peaks still wrapped in thin veils of mist. A narrow river cuts through the landscape, catching the light and scattering it in silver ripples. Clusters of wildflowers dot the open fields, their colors flickering gently as the breeze moves past them. Above, the sky stretches wide and calm, painted with long strokes of pale gold and quiet clouds drifting lazily across the horizon. The whole scene feels suspended in a peaceful stillness, as if the world were taking a quiet breath before the day truly begins.

Subtitle

A soft wind drifts across the valley, brushing through tall grass that bends like waves beneath a slow morning sun. In the distance, mountains rise in layered shades of blue, their peaks still wrapped in thin veils of mist. A narrow river cuts through the landscape, catching the light and scattering it in silver ripples. Clusters of wildflowers dot the open fields, their colors flickering gently as the breeze moves past them. Above, the sky stretches wide and calm, painted with long strokes of pale gold and quiet clouds drifting lazily across the horizon. The whole scene feels suspended in a peaceful stillness, as if the world were taking a quiet breath before the day truly begins.

Subtitle

A soft wind drifts across the valley, brushing through tall grass that bends like waves beneath a slow morning sun. In the distance, mountains rise in layered shades of blue, their peaks still wrapped in thin veils of mist. A narrow river cuts through the landscape, catching the light and scattering it in silver ripples. Clusters of wildflowers dot the open fields, their colors flickering gently as the breeze moves past them. Above, the sky stretches wide and calm, painted with long strokes of pale gold and quiet clouds drifting lazily across the horizon. The whole scene feels suspended in a peaceful stillness, as if the world were taking a quiet breath before the day truly begins.

Subtitle

A soft wind drifts across the valley, brushing through tall grass that bends like waves beneath a slow morning sun. In the distance, mountains rise in layered shades of blue, their peaks still wrapped in thin veils of mist. A narrow river cuts through the landscape, catching the light and scattering it in silver ripples. Clusters of wildflowers dot the open fields, their colors flickering gently as the breeze moves past them. Above, the sky stretches wide and calm, painted with long strokes of pale gold and quiet clouds drifting lazily across the horizon. The whole scene feels suspended in a peaceful stillness, as if the world were taking a quiet breath before the day truly begins.

Subtitle

A soft wind drifts across the valley, brushing through tall grass that bends like waves beneath a slow morning sun. In the distance, mountains rise in layered shades of blue, their peaks still wrapped in thin veils of mist. A narrow river cuts through the landscape, catching the light and scattering it in silver ripples. Clusters of wildflowers dot the open fields, their colors flickering gently as the breeze moves past them. Above, the sky stretches wide and calm, painted with long strokes of pale gold and quiet clouds drifting lazily across the horizon. The whole scene feels suspended in a peaceful stillness, as if the world were taking a quiet breath before the day truly begins.

---
import { AnimateScroll } from "@/src/components/hybrid-astro-ui/animate-scroll"
---
<AnimateScroll threshold={0.5} class="border px-5 py-2 rounded-xl [&_p]:opacity-80!">
    <h2 class="text-center">Example containing only text, simple animation</h2>

    {  
        Array.from({length:5}, () => ({
            subtitle: "Subtitle",
            content: `A soft wind drifts across the valley, brushing through tall grass that bends 
            like waves beneath a slow morning sun. In the distance, mountains rise in layered
            shades of blue, their peaks still wrapped in thin veils of mist. A narrow river
            cuts through the landscape, catching the light and scattering it in silver ripples.
            Clusters of wildflowers dot the open fields, their colors flickering gently as 
            the breeze moves past them. Above, the sky stretches wide and calm, painted with 
            long strokes of pale gold and quiet clouds drifting lazily across the horizon. 
            The whole scene feels suspended in a peaceful stillness, as if the world were 
            taking a quiet breath before the day truly begins.`})).
            map(item => 
            <div>
                <h3>{item.subtitle}</h3>
                <p>
                    {item.content}
                </p>
            </div>
        )
    }
    
</AnimateScroll>