Parallax Grid
Gallery columns drifting at different rates for depth.
0.7 KB gzippedDeps: motion/reactReduced-motion safeBase UI & Radix compatible
Installation
npx shadcn@latest add https://innsite.com.mx/r/parallax-grid.jsonInstalls with: motion
Source
"use client";
import { useRef } from "react";
import { motion, useReducedMotion, useScroll, useTransform } from "motion/react";
import { cn } from "@/lib/utils";
interface ParallaxGridProps {
/** Each child becomes one tile; columns drift at different speeds */
children: React.ReactNode[];
/** Maximum vertical drift in px */
depth?: number;
className?: string;
}
/**
* Image or card grid whose columns drift at different rates as the page
* scrolls, giving a gallery a sense of depth.
*/
export function ParallaxGrid({
children,
depth = 90,
className,
}: ParallaxGridProps) {
const ref = useRef<HTMLDivElement>(null);
const reducedMotion = useReducedMotion();
const { scrollYProgress } = useScroll({
target: ref,
offset: ["start end", "end start"],
});
// Three columns: outer ones lead, the middle one lags.
const fast = useTransform(scrollYProgress, [0, 1], [depth, -depth]);
const slow = useTransform(scrollYProgress, [0, 1], [depth * 0.4, -depth * 0.4]);
const lagging = useTransform(scrollYProgress, [0, 1], [-depth * 0.3, depth * 0.3]);
const tracks = [fast, lagging, slow];
return (
<div
ref={ref}
data-slot="parallax-grid"
className={cn("grid grid-cols-2 gap-4 md:grid-cols-3", className)}
>
{children.map((child, i) => (
<motion.div
key={i}
style={reducedMotion ? undefined : { y: tracks[i % 3] }}
className="will-change-transform"
>
{child}
</motion.div>
))}
</div>
);
}

