Examples
Interactive demos showing Pendu in action.
Dynamic Add & Remove
Adjust the slider to add or remove images. The gallery animates each transition using FLIP animations.
DynamicGallery.tsx
const [photos, setPhotos] = useState(allPhotos);
// Add
setPhotos([...photos, newPhoto]);
// Remove
setPhotos(photos.filter(p => p.id !== removeId));
// The gallery animates automatically
<Pendu gap={12}>
{photos.map(p => (
<Pendu.Image key={p.id} {...p} />
))}
</Pendu>Gap & Seed
Control spacing and layout randomization. Same seed always produces the same layout.
Gallery.tsx
<Pendu gap={12} seed={42}>
<Pendu.Image src="/photo.jpg" width={1200} height={800} alt="Photo" />
<Pendu.Image src="/portrait.jpg" width={800} height={1200} alt="Portrait" />
</Pendu>Container Modes
Pendu fills whatever container you give it — fixed height, percentage, or viewport units.
Fixed 300px height
Dynamic height (auto)
ContainerModes.tsx
{/* Fixed height — gallery scales to fit */}
<div style={{ height: 400 }}>
<Pendu gap={8}>{...}</Pendu>
</div>
{/* Dynamic — gallery grows with content */}
<div style={{ width: '100%' }}>
<Pendu gap={8}>{...}</Pendu>
</div>
{/* Viewport units */}
<div style={{ height: '60vh', width: '80vw' }}>
<Pendu gap={8}>{...}</Pendu>
</div>Size Constraints
Control minimum and maximum frame widths. Useful for keeping portrait images visible and wide panoramas in check.
SizeConstraints.tsx
<Pendu gap={12} minItemWidth={120} maxItemWidth={400}>
<Pendu.Image src="/portrait.jpg" width={800} height={1200} />
<Pendu.Image src="/panorama.jpg" width={2400} height={600} />
</Pendu>Layout Callback
Subscribe to layout changes with onLayoutChange. Useful for lightboxes, tooltips, or analytics.
LayoutCallback.tsx
<Pendu gap={12} onLayoutChange={(result) => {
console.log(`Placed ${result.stats.placed} frames`);
console.log('Bounds:', result.bounds);
}}>
<Pendu.Image src="/photo.jpg" width={1200} height={800} />
</Pendu>Lazy Loading
Enable native browser lazy loading with a single prop. Images below the fold load on demand, keeping initial page load fast.
LazyLoading.tsx
// All images lazy-loaded
<Pendu lazy gap={12}>
<Pendu.Image src="/photo.jpg" width={1200} height={800} alt="Photo" />
</Pendu>
// Per-image control
<Pendu gap={12}>
<Pendu.Image src="/hero.jpg" width={1200} height={800} loading="eager" />
<Pendu.Image src="/below.jpg" width={800} height={1200} loading="lazy" />
</Pendu>