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>