mason-grid
v0.4.0
Published
Performant virtualized masonry grid for React
Readme
mason-grid
A performant, virtualized masonry grid component for React with TypeScript support.
Features
- Virtualized rendering – Only renders items visible in the viewport for optimal performance
- Responsive layout – Automatically adjusts columns based on container width
- TypeScript support – Full type safety out of the box
- Lightweight – Zero dependencies (besides React)
- Flexible – Customizable column widths, gaps, and render functions
- Smooth scrolling – Configurable viewport buffering for seamless experience
Installation
npm install mason-gridUsage
Basic Example
import { Masonry, MasonryItem } from 'mason-grid';
interface ImageItem extends MasonryItem {
id: string;
width: number;
height: number;
url: string;
title: string;
}
function Gallery() {
const images: ImageItem[] = [
{ id: '1', width: 400, height: 600, url: '/image1.jpg', title: 'Image 1' },
{ id: '2', width: 400, height: 400, url: '/image2.jpg', title: 'Image 2' },
// ... more items
];
return (
<Masonry
data={images}
renderItem={(item, position) => (
<div>
<img src={item.url} alt={item.title} style={{ width: '100%' }} />
<h3>{item.title}</h3>
</div>
)}
minColumnWidth={250}
gap={16}
/>
);
}API
<Masonry> Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| data | T[] | required | Array of items to display. Each item must extend MasonryItem |
| renderItem | (item: T, position: MasonryPosition) => ReactNode | required | Function to render each item |
| minColumnWidth | number | 250 | Minimum width of each column in pixels |
| gap | number | 16 | Gap between items in pixels |
| bufferScreens | number | 2 | Number of viewport heights to render above/below visible area |
| loading | boolean | false | Loading state indicator |
| skeletonCount | number | 20 | Number of skeleton items to show when loading |
| className | string | '' | CSS class for the container |
| itemClassName | string | '' | CSS class for each item wrapper |
MasonryItem Interface
Your data items must extend this interface:
interface MasonryItem {
id: string | number; // Unique identifier
width: number; // Original width of the item
height: number; // Original height of the item
}MasonryPosition Interface
Position data passed to renderItem:
interface MasonryPosition {
id: string | number; // Item ID
x: number; // X position in pixels
y: number; // Y position in pixels
width: number; // Rendered width in pixels
height: number; // Rendered height in pixels
}Advanced Usage
Using the useMasonry Hook
For more control, you can use the useMasonry hook directly:
import { useMasonry } from 'mason-grid';
function CustomMasonry() {
const [containerWidth, setContainerWidth] = useState(0);
const { positions, containerHeight } = useMasonry({
items: myItems,
containerWidth,
minColumnWidth: 300,
gap: 20,
});
// Custom rendering logic using positions...
}Custom Styling
<Masonry
data={items}
renderItem={(item) => (
<div className="rounded-lg shadow-lg overflow-hidden bg-white">
<img src={item.url} alt={item.title} className="w-full" />
</div>
)}
className="mx-auto max-w-7xl px-4"
itemClassName="transition-transform hover:scale-105"
gap={24}
/>How It Works
- Layout calculation – The component calculates column positions based on container width and item dimensions
- Virtualization – Only items within the viewport (plus buffer) are rendered to the DOM
- Responsive – Automatically recalculates layout on window resize
- Performance – Uses absolute positioning and transforms for smooth rendering
Requirements
- React >= 19
- react-dom >= 19
