Why I Built a Responsive Image Strip Gallery (and Published It for Every Framework)
A few weeks ago I ran into a layout problem that sounds simple on paper: put portrait and landscape photos in the same row, aligned, without cropping them into ugly square boxes.
It turned out that no gallery — not Squarespace's built-in options, not the popular npm galleries — actually solves this cleanly. So I built one myself: image-strip-gallery, a fixed-column strip gallery that works in React, Vue, Angular, Svelte, plain JS, and as a copy-paste block for Squarespace and WordPress.
Here's the problem, why the usual answers fall short, and how the package solves it.
The problem: masonry breaks on mixed orientations
Squarespace's Section and Masonry gallery types are great for uniform grids, but they have a specific weakness — they don't keep portrait and landscape images aligned on the same row. Because masonry layouts stack images into columns of varying height, a tall portrait photo and a wide landscape photo end up with mismatched row baselines. You lose that clean, editorial "strip" look where six photos of different shapes sit level with each other.
This isn't a hypothetical problem — I found a whole Squarespace forum thread of people asking for exactly this and getting workarounds instead of a real fix.
The usual workaround — and why it's a bad trade
The common fix is to force every image into the same crop box: uniform width, uniform height, object-fit: cover. Rows do line up — but you lose composition. A landscape shot gets cropped into a square, a portrait gets its subject clipped. For photography-led sites (portfolios, product shots, editorial layouts), that's not acceptable.
What the package actually does
Instead of cropping, the gallery keeps each image's natural aspect ratio and solves alignment at the row level:
- A fixed number of images per row (default: 6 desktop, 2 mobile)
- Every row shares one height
- Each image's width is calculated from its own aspect ratio to fit that shared row height
- Portrait and landscape images sit side by side in the same row, fully aligned, uncropped
The result is the "strip" look people were asking for on that forum thread — without the crop-box compromise.
Built for how people actually ship sites today
Because I do full-stack work across Laravel, Vue, and React projects — and because half my audience for this needed a no-code option — I shipped it two ways:
- A copy-paste HTML/CSS/JS version for Squarespace and WordPress — no npm, no build step, just paste into a Code Block and Custom CSS panel.
- An npm package with dedicated entry points for React/Next.js and Vue/Nuxt, plus a vanilla-JS core that works directly in Angular, Svelte, or plain HTML.
It's lightweight (no jQuery dependency), SSR-safe for Next.js, includes an optional row-by-row fade-in animation, and every layout parameter — columns, gap, breakpoint, row height, animation timing — is configurable.
npm install @meerathanki09/image-strip-gallery
import { ResponsiveImageStripGallery } from '@meerathanki09/image-strip-gallery/react';
<ResponsiveImageStripGallery
images={images}
columns={{ desktop: 6, mobile: 2 }}
onImageClick={(image, index) => console.log(index, image)}
/>
Why I'm sharing this
I build a lot of client sites where photography matters — portfolios, product pages, event galleries — and I kept hitting this same wall. Rather than solving it once per project, I built it as a reusable, framework-agnostic package and published it publicly so anyone hitting the same forum thread I found doesn't have to choose between misaligned rows and cropped photos.
If you're dealing with the same layout problem, the package is free and MIT-licensed:
👉 npmjs.com/package/@meerathanki09/image-strip-gallery
Feedback, issues, and PRs welcome.
Top comments (4)
Nice work. I like that you focused on preserving the original aspect ratio instead of forcing everything into uniform crop boxes. One question though: how does the layout handle edge cases like an entire row of ultra-wide panoramas or very tall portrait images? Do you normalize the target row height dynamically, or do you keep a fixed height and accept horizontal overflow/very narrow widths? Those extremes are usually where gallery algorithms reveal their real trade-offs.
Full rows normalize height dynamically from aspect ratios so the row always fills the width with no overflow/cropping. Ultra-wide rows get shorter; ultra-tall portrait rows get taller. Only the last incomplete row uses a fixed fallback height. No min/max clamp yet — that’s the main edge-case trade-off.
Thanks for the explanation! That makes sense. Using dynamic row heights for complete rows and a fixed fallback for the last row is a sensible trade-off. A configurable min/max row height could be a nice future addition—it would keep extreme panoramas or portrait-heavy rows from becoming visually unbalanced while still preserving the original aspect ratios. Nice work!
Thank you so much @merbayerp