Zero-dependency, virtualized masonry layouts for vanilla JS and React. Render 10,000+ items at 60fps with automatic column balancing.
npm install smart-masonry-grid
Why Choose Us
Built for performance, designed for simplicity.
No bloat. Uses native ResizeObserver and IntersectionObserver. Your bundle stays light — under 5KB gzipped for the core.
Only renders what's visible. Binary search over sorted positions gives O(log n) lookups. Handle 10,000+ items without breaking a sweat.
Auto-fit, fixed count, or breakpoint-based. Named breakpoints (sm/md/lg/xl) or custom pixel values. Columns adapt instantly on resize.
Smooth slide-up-and-fade entrance for new items. Configurable duration, easing, and offset. Enable with a single prop.
Vanilla JS MasonryGrid class for any framework. React components for the React ecosystem. Same engine, two interfaces.
CSS columns fallback for server-rendered HTML. Hydrates seamlessly on the client. No flash of unstyled content.
The Difference
Most masonry libraries are abandoned, React-only, or missing critical features.
| Feature | smart-masonry-grid | masonry-layout | react-masonry-css | masonic | @mui/lab |
|---|---|---|---|---|---|
| Zero dependencies | ✓ | ✗ | ✓ | ✗ | ✗ |
| Virtualization (10K+ items) | ✓ | ✗ | ✗ | ✓ | ✗ |
| SSR / Next.js support | ✓ | ✗ | ✗ | Partial | Buggy |
| Vanilla JS + React | ✓ | Vanilla only | React only | React only | React only |
| Built-in animations | ✓ | ✗ | ✗ | ✗ | ✗ |
| Built-in infinite scroll | ✓ | ✗ | ✗ | ✓ | ✗ |
| TypeScript (built-in) | ✓ | ✗ | Partial | ✓ | ✓ |
| Responsive breakpoints | 4 modes | ✗ | Basic | ✗ | Basic |
| Actively maintained | ✓ | Barely | ✗ (4yr+) | Partial | ✓ |
No other library combines zero-dependency virtualization, SSR support, and multi-framework support in one package.
Simple API
Import, wrap your items, done. Automatic measurement, positioning, and resize handling. No configuration needed for common use cases.
import { Masonry } from 'smart-masonry-grid/react'; function Gallery({ photos }) { return ( <Masonry columns={{ sm: 2, md: 3, lg: 4 }} gap={16} animate > {photos.map((photo) => ( <img key={photo.id} src={photo.src} alt={photo.alt} /> ))} </Masonry> ); }
// Render 10,000 items — only visible ones in the DOM <VirtualMasonry totalItems={10_000} renderItem={(index) => <Card index={index} />} height={600} columns={4} gap={16} animate />
Virtualization
VirtualMasonry only renders items visible in the viewport plus a configurable overscan buffer. Binary search keeps lookups at O(log n).
Get started in seconds. Zero config required.