Inertia gallery
An endless strip of frames you push with the wheel or a drag; it coasts, snaps by intent and morphs between list and slider.
Behaviour
- Wheel or drag adds velocity; the strip coasts, then settles by intent: a nudge returns, anything more moves at least one frame.
- Each image is zoomed past its frame and drifts against the frame's distance from the centre (parallax).
- Switching layout moves every frame to its new spot over 1.5s, outer frames first.
- Arrow keys move one frame and Home / End jump to the ends while the strip has focus; Enter opens the centred frame's link.
- Touch only takes horizontal swipes (touch-action: pan-y), so the page still scrolls on phones.
- The frame loop runs only while something moves and pauses off screen.
- Reduced motion: no parallax or coasting (jumps to the settled frame), layout switches crossfade, no intro.
Props
| Prop | Type | Description |
|---|---|---|
| items | { src?: string; node?: ReactNode; alt?: string; href?: string; title?: ReactNode }[] | Frames. node draws instead of an image; an empty frame shows bg-muted. |
| layout | "list" | "slider" | Controlled layout. Pair with onLayoutChange. |
| defaultLayout | "list" | "slider"default "list" | Uncontrolled starting layout. |
| onLayoutChange | (layout) => void | Fires when the bar's List / Slider buttons ask for a layout. |
| onActiveChange | (index: number) => void | Fires when the centred item changes. |
| intro | booleandefault false | Play the squares intro the first time it scrolls into view. |
| friction | numberdefault 0.97 | Velocity kept per 60fps frame; higher coasts further. |
| frameWidth | numberdefault 240 | Largest list frame width in px; slider frames are 2x. Both shrink to fit. |
| frameHeight | numberdefault 320 | Largest list frame height in px. |
| bar | booleandefault true | Bottom bar with title, counter and the List / Slider buttons. |
| label | stringdefault "Gallery" | Accessible name. |
Installation
npx shadcn@latest add https://purrfectui.com/r/inertia-gallery.jsonHow to use
import { InertiaGallery } from "@/components/ui/inertia-gallery";
<div className="h-[560px]">
<InertiaGallery items={[{ src: "/a.jpg", alt: "A", title: "A", href: "/work/a" }, { node: <Art />, title: "B" }]} />
</div>Source code
Loading…
Credits
Ported from poinu.vercel.app.
License
MIT. Copy it into your project and change it as you like.









