react-responsive-masonry
A lightweight React masonry grid built with pure CSS flexbox — no JS layout engine, no image preloading, no dependencies beyond prop-types.
Repository Health
Technical Analysis
react-responsive-masonry gives React apps a Pinterest-style masonry grid without pulling in a heavyweight layout engine. It ships two components — Masonry, which distributes children across a fixed number of columns using flexbox, and ResponsiveMasonry, which wraps it and swaps the column count and gutter size at configurable pixel breakpoints as the browser resizes.
Internally, Masonry measures each child’s rendered height via refs after the initial mount, then greedily assigns items to whichever column currently has the smallest total height — a classic shortest-column-first packing heuristic, recomputed only when children or column count change (guarded by shouldComponentUpdate and getDerivedStateFromProps to avoid needless re-renders). An optional sequential prop skips this height-based redistribution and keeps items in their original document order, trading a slightly less even layout for full control over ordering.
Because it depends only on prop-types and does no DOM measurement beyond getBoundingClientRect, it’s a reasonable fit for teams that want masonry layout without adopting a full grid/virtualization library, and it ships CJS, ESM, and UMD builds plus first-party TypeScript declarations.
What You Get
Masonrycomponent that packs children into N flexbox columns using a shortest-column-first height-balancing algorithmResponsiveMasonrywrapper that changescolumnsCountandgutterat configurable pixel breakpoints as the window resizes- A
sequentialprop to opt out of height-based reordering and preserve original child order - Customizable container/item tags (
containerTag,itemTag) and inlinestyle/itemStyle/classNameoverrides - First-party TypeScript type declarations (
types/index.d.ts) alongside CJS, ESM, and UMD builds - No layout dependencies beyond
prop-types— no image-preloading, virtualization, or measurement libraries pulled in
Common Use Cases
- Image/photo galleries where items have varying aspect ratios and a Pinterest-style grid looks better than a uniform grid
- Blog or portfolio card layouts where content height varies per card and columns should stay visually balanced
- Product or media listing pages that need to reflow from 1 to 3+ columns as the viewport narrows or widens
- Any React UI needing masonry layout without adopting a larger grid/virtualization library as a dependency
Under The Hood
Architecture
The library is two independent components composed together rather than one monolith. Masonry (src/Masonry/index.js) is a class component that owns the column-packing logic: getDerivedStateFromProps rebuilds an equal-count column split and a ref per child whenever children or columnsCount change, then componentDidUpdate triggers distributeChildren(), which waits until every child ref reports a measured height (via getBoundingClientRect) and only then performs one greedy pass — assigning each child to the column with the current minimum total height. ResponsiveMasonry (src/ResponsiveMasonry/index.js) is a separate functional component that tracks window.innerWidth through a resize-listener hook (guarded with useIsomorphicLayoutEffect for SSR safety), derives the active columnsCount/gutter from sorted breakpoint maps, and injects those values into its Masonry child via React.cloneElement — so the two components only interact through props, not shared internal state. If the core distributeChildren height-balancing pass changed, the entire rebalancing behavior for every consumer would change at once, since there’s no alternate packing strategy plugged in elsewhere.
Tech Stack
The runtime dependency surface is deliberately minimal: prop-types for the only runtime dependency, react/react-dom as peer dependencies (built and tested against React 16), and nwb as the build tool producing CommonJS, ES module, and UMD bundles plus the hand-authored TypeScript declaration file in types/. There’s no bundler config beyond nwb.config.js, no CSS-in-JS or external styling library — all layout is done via inline style objects using flexbox properties (display: flex, gap, flex: 1), so the only stylesheet dependency at runtime is the browser’s own CSS engine.
Code Quality
Tests live alongside each component (Masonry/index.test.js, ResponsiveMasonry/index.test.js) and use Jest with Enzyme’s mount plus the React 16 adapter — a testing stack that predates React’s official Testing Library recommendation, and coverage is limited to a couple of smoke-render assertions (default render, custom container/item tags) rather than testing the height-balancing algorithm itself. ESLint plus Prettier are wired through .eslintrc.js/.prettierrc and enforced pre-commit via Husky and lint-staged, and commitlint enforces conventional commit messages, but there is no CI badge currently passing beyond a Travis config that predates the repo’s more recent activity, and prop validation relies on runtime PropTypes rather than compile-time enforcement in the JS source itself (the .d.ts file is maintained separately by hand).
What Makes It Unique
The distinguishing choice is doing masonry layout with plain flexbox and a runtime height-measurement pass instead of either (a) CSS Grid’s grid-template-rows: masonry (not broadly supported), or (b) absolute-positioning libraries that require knowing image dimensions upfront. The shortest-column-first greedy heuristic is a well-known bin-packing approximation, not a novel algorithm, and the library trades perfect packing optimality for simplicity and a near-zero dependency footprint — a reasonable but standard engineering tradeoff rather than a technical innovation.