A lightweight React utility for creating responsive masonry-style layouts with automatic height estimation and column distribution.
- Features
- Environment Compatibility
- Installation
- Usage
- Responsive Layout with
breakpoints
- Props
- Utility Functions
- Experimental Features
- How It Works
- Development
- License
- Contributing
- 🎯 Simple and intuitive API
- 📱 Responsive column-based layout
- 📏 Automatic height estimation
- 🎨 Customizable gap between items
- 🔄 Support for dynamic content
- 🚀 Zero dependencies (except React)
- 📦 TypeScript support
- 🛠️ Utility functions for common tasks
This component is primarily designed for client-side use in React applications. While it doesn't use React hooks, it relies on client-side calculations for optimal layout and height estimation.
- ✅ Client-side React applications
- ✅ Browser environments
- ✅ React 17+ and React 18+
- ✅ Next.js client components (with 'use client' directive)
- ✅ Client-side rendered pages
To use this component with server components in frameworks like Next.js, follow these guidelines:
-
Use the
'use client'
directive at the top of the file where you import and use the Layouter:"use client"; import Layouter from "react-broken-layouter";
-
Provide explicit heights via
getHeight
orestimateHeight
props to ensure consistent layout:<Layouter cols={3} items={items} render={Item} getHeight={(item) => item.height} // Provide explicit heights />
- ❌ Server Components without 'use client' directive
- ❌ Server-side rendering without proper client-side hydration
- ❌ Static site generation without client-side JavaScript
⚠️ Height estimation is most accurate in client environments⚠️ For server-side rendering, consider providing explicit heights viagetHeight
orestimateHeight
props⚠️ Dynamic content may require client-side re-rendering for optimal layout
npm install react-broken-layouter
# or
yarn add react-broken-layouter
A simple setup with a fixed number of columns:
import Layouter from "react-broken-layouter";
const items = [
{ id: 1, content: "Item 1" },
{ id: 2, content: "Item 2" },
// ...
];
const Item = ({ item }) => (
<div style={{ padding: "1rem", background: "#f0f0f0" }}>{item.content}</div>
);
export default function App() {
return (
<Layouter
cols={3} // Fixed column count
items={items}
render={Item} // Render component
gap={16} // Space between items
getId={(item) => item.id} // Unique key for each item
/>
);
}
You can provide a custom render function that returns a component to display each item. The function receives an item
prop, which you can pass to your component:
const YourComponent = ({ item }) => (
<div style={{ padding: "1rem", background: "#e0e0e0" }}>{item.content}</div>
);
<Layouter
cols={3} // Fixed column count
items={items}
render={(props) => <YourComponent {...props} />} // Custom render function
gap={16} // Space between items
getId={(item) => item.id} // Unique key for each item
/>;
Note: The
render
prop expects a component that accepts anitem
prop. Using a function allows dynamic rendering while maintaining compatibility.
Use the breakpoints
prop to override the default cols
value based on screen width, ideal for responsive layouts:
<Layouter
cols={1} // Default to 1 column (e.g., for mobile)
items={items}
render={Item}
gap={16}
getId={(item) => item.id}
breakpoints={{
768: { cols: 2 },
1024: { cols: 3 },
1440: { cols: 4 },
}}
/>
This dynamically sets:
- 1 column below 768px (using
cols
) - 2 columns from 768px to 1023px
- 3 columns from 1024px to 1439px
- 4 columns at 1440px and above
Prop | Type | Required | Default | Description |
---|---|---|---|---|
cols |
number | ✅ | - | Default number of columns (overridden by breakpoints if provided) |
breakpoints |
{ [width: number]: { cols: number } } | ❌ | - | Map of viewport widths to column counts for responsive behavior |
items |
any[] | ✅ | - | List of items to display |
render |
React.FC<{ item: any }> | ✅ | - | Component to render each item (can be a function returning a component) |
gap |
number | ❌ | 16 | Gap between items (px) |
getId |
(item: any) => string | number | ❌ | - | Optional function to get unique ID for each item |
getHeight |
(item: any) => number | ❌ | - | Exact item height (for layout optimization) |
estimateHeight |
(item: any) => number | ❌ | - | Estimate item height if exact value isn't available |
mediaHeight |
number | ❌ | - | Additional height buffer (e.g., for images or media content) |
These utility functions simplify common tasks like height estimation and ID generation:
-
heightEstimator
Estimates the total height based on an array of strings or numbers. Useful for calculating content heights.import { heightEstimator } from "react-broken-layouter"; // Example usage const content = ["Hello", "World", 100]; const estimatedHeight = heightEstimator(content); // Returns: (5 * 0.35) + (5 * 0.35) + 100 = 103.5
-
getRandomId
Generates a random string ID. Useful for creating unique keys when none are provided.import { getRandomId } from "react-broken-layouter"; // Example usage const uniqueId = getRandomId(); // Returns something like: "x7f9k2m"
-
isObject
Checks if a value is a plain object (not an array or null).import { isObject } from "react-broken-layouter"; // Example usage isObject({}); // true isObject([]); // false isObject(null); // false isObject("string"); // false
Note: These features are experimental and may not work perfectly in all scenarios. Test thoroughly with your use case.
The height estimation features (getHeight
and estimateHeight
) are currently experimental and may be subject to change in future versions. These features provide ways to control the height of items in the layout:
-
getHeight
: Allows you to provide exact heights for items -
estimateHeight
: Lets you implement custom height estimation logic
The Layouter component:
- Estimates the height of each item based on content length
- Distributes items across columns to maintain balanced heights
- Renders items in a responsive grid layout
# Install dependencies
npm install
# Run development build
npm run dev
# Build for production
npm run build
MIT © Hassan Mohamed
We’d love to improve React Broken Layouter with your help! Contributions are welcome—please feel free to submit a Pull Request or open an issue to discuss your ideas.