The ImageTrail displays framed media following the user's pointer with physics-based momentum. It supports rounded frame variants, composable captions, custom keyframe animations, distance thresholds, and configurable stacking.
Preview
Usage
Installation
$ npx shadcn@latest add https://spark-ui-olive.vercel.app/r/image-trail.json
Basic Example
import {
ImageTrail,
ImageTrailItem,
ImageTrailItemCaption,
} from "@/components/image-trail";
const IMAGES = [
"/images/trail-1.jpg",
"/images/trail-2.jpg",
"/images/trail-3.jpg",
"/images/trail-4.jpg",
"/images/trail-5.jpg",
];
export default function App() {
return (
<ImageTrail
threshold={90}
intensity={0.2}
repeatChildren={12}
keyframes={{
scale: [0.3, 1, 1, 0.3],
rotate: [0, -10, 10, 0],
opacity: [0, 1, 1, 0],
}}
keyframesOptions={{
duration: 1.2,
times: [0, 0.05, 0.85, 1],
ease: "easeOut",
}}
trailElementAnimationKeyframes={{
x: { duration: 0.35, type: "tween", ease: "easeOut" },
y: { duration: 0.35, type: "tween", ease: "easeOut" },
}}
>
{IMAGES.map((src, index) => (
<ImageTrailItem key={index} radius="xl" variant="framed">
<img
src={src}
alt={`Trail photo ${index + 1}`}
className="h-full w-full object-cover"
/>
<ImageTrailItemCaption>Photo {index + 1}</ImageTrailItemCaption>
</ImageTrailItem>
))}
</ImageTrail>
);
}
Properties
| Prop | Type | Default | Description |
|---|---|---|---|
as | ElementType | "div" | HTML element to render the container as. |
threshold | number | 100 | Distance in pixels the mouse must travel to spawn the next element. |
intensity | number | 0.3 | Momentum factor (0.0001 to 1.0) for tracking lag. Lower is smoother. |
keyframes | DOMKeyframesDefinition | undefined | Framer Motion keyframes defining the animation sequence. |
keyframesOptions | AnimationOptions | undefined | Framer Motion options for the keyframes animation. |
trailElementAnimationKeyframes | object | tween/easeOut | Framer Motion options for the tracking movement. |
repeatChildren | number | 3 | Number of times children are duplicated to prevent trail gaps. |
variant | "plain" | "framed" | "glass" | "framed" | Visual treatment applied to ImageTrailItem. |
radius | "none" | "sm" | "md" | "lg" | "xl" | "full" | "xl" | Corner radius applied to an ImageTrailItem and its direct image. |
baseZIndex | number | 0 | Starting z-index for the trailing items. |
zIndexDirection | "new-on-top" | "old-on-top" | "new-on-top" | Stacking behavior ('new-on-top' or 'old-on-top'). |




