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>