React-Grid-Layout

React-Grid-Layout is a grid layout system much like Packery or
Gridster, for React.
Unlike those systems, it is responsive and supports breakpoints. Breakpoint layouts can be provided by the user
or autogenerated.
RGL is React-only and does not require jQuery.

GIF from production usage on BitMEX.com
[Demo | Changelog | CodeSandbox Editable demo]
Table of Contents
What's New in v2
Version 2 is a complete TypeScript rewrite with a modernized API:
- Full TypeScript support - First-class types, no more
@types/react-grid-layout
- React Hooks - New
useContainerWidth, useGridLayout, and useResponsiveLayout hooks
- Composable Configuration - Group related props into focused interfaces:
gridConfig - cols, rowHeight, margin, padding
dragConfig - enable, handle, cancel, bounded
resizeConfig - enable, handles
positionStrategy - transform vs absolute positioning
compactor - vertical, horizontal, or custom algorithms
- Modular architecture - Import only what you need:
react-grid-layout - React components and hooks (v2 API)
react-grid-layout/core - Pure layout algorithms (framework-agnostic)
react-grid-layout/legacy - v1 flat props API for migration
react-grid-layout/extras - Optional components like GridBackground
- Smaller bundle - Tree-shakeable ESM and CJS builds
Breaking Changes
See the RFC for detailed migration examples.
width prop required | Use useContainerWidth hook or provide your own measurement |
onDragStart threshold | Now fires after 3px movement, not on mousedown. Use onMouseDown for immediate response |
| Immutable callbacks | Callback parameters are read-only. Use onLayoutChange or constraints instead of mutation |
data-grid in legacy only | v2 requires explicit layout prop. Use legacy wrapper for data-grid |
| Pluggable compaction | Compaction is now pluggable via Compactor interface. Optional fast O(n log n) algorithm in /extras |
| UMD bundle removed | Use a bundler (Vite, webpack, esbuild) |
verticalCompact removed | Use compactType={null} or compactor={noCompactor} |
Migrating from v1
Quick migration - change your import to use the legacy wrapper:
- import GridLayout, { Responsive, WidthProvider } from 'react-grid-layout';
+ import GridLayout, { Responsive, WidthProvider } from 'react-grid-layout/legacy';
This provides 100% runtime API compatibility with v1.
TypeScript users: If you were using @types/react-grid-layout, note that v2 includes its own types with some naming changes:
RGL.Layout | LayoutItem | Single grid item |
RGL.Layout[] | Layout | Array of items |
RGL.Layouts | ResponsiveLayouts | Breakpoint → layout map |
- import RGL from 'react-grid-layout';
- const item: RGL.Layout = { i: 'a', x: 0, y: 0, w: 1, h: 1 };
- const layouts: RGL.Layouts = { lg: [item] };
+ import { LayoutItem, ResponsiveLayouts } from 'react-grid-layout/legacy';
+ const item: LayoutItem = { i: 'a', x: 0, y: 0, w: 1, h: 1 };
+ const layouts: ResponsiveLayouts = { lg: [item] };
Full migration - adopt the v2 API for new features and better tree-shaking:
import ReactGridLayout, { useContainerWidth, verticalCompactor } from 'react-grid-layout';
function MyGrid() {
const { width, containerRef, mounted } = useContainerWidth();
return (
<div ref={containerRef}>
{mounted && (
<ReactGridLayout
width={width}
layout={layout}
gridConfig={{ cols: 12, rowHeight: 30 }}
dragConfig={{ enabled: true, handle: '.handle' }}
compactor={verticalCompactor}
>
{children}
</ReactGridLayout>
)}
</div>
);
}
| Existing v1 codebase | react-grid-layout/legacy |
| New project | v2 API with hooks |
| Custom compaction | v2 with custom Compactor |
| SSR | v2 with measureBeforeMount: true |
Demos
Projects Using React-Grid-Layout
Know of others? Create a PR to let me know!
Features
- 100% React - no jQuery
- Full TypeScript support
- Compatible with server-rendered apps
- Draggable widgets
- Resizable widgets
- Static widgets
- Configurable packing: horizontal, vertical, or off
- Bounds checking for dragging and resizing
- Widgets may be added or removed without rebuilding grid
- Layout can be serialized and restored
- Responsive breakpoints
- Separate layouts per responsive breakpoint
- Grid Items placed using CSS Transforms
- Compatibility with
<React.StrictMode>
| >= 2.0.0 | React 18+, TypeScript |
| >= 0.17.0 | React 16 & 17 |
Installation
npm install react-grid-layout
Include the stylesheets in your application:
import "react-grid-layout/css/styles.css";
import "react-resizable/css/styles.css";
Or link them directly:
<link rel="stylesheet" href="/node_modules/react-grid-layout/css/styles.css" />
<link rel="stylesheet" href="/node_modules/react-resizable/css/styles.css" />
Quick Start
import ReactGridLayout, { useContainerWidth } from "react-grid-layout";
import "react-grid-layout/css/styles.css";
import "react-resizable/css/styles.css";
function MyGrid() {
const { width, containerRef, mounted } = useContainerWidth();
const layout = [
{ i: "a", x: 0, y: 0, w: 1, h: 2, static: true },
{ i: "b", x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4 },
{ i: "c", x: 4, y: 0, w: 1, h: 2 }
];
return (
<div ref={containerRef}>
{mounted && (
<ReactGridLayout
layout={layout}
width={width}
gridConfig={{ cols: 12, rowHeight: 30 }}
>
<div key="a">a</div>
<div key="b">b</div>
<div key="c">c</div>
</ReactGridLayout>
)}
</div>
);
}
You can also define layout on children using data-grid:
<ReactGridLayout width={width} gridConfig={{ cols: 12, rowHeight: 30 }}>
<div key="a" data-grid={{ x: 0, y: 0, w: 1, h: 2, static: true }}>
a
</div>
<div key="b" data-grid={{ x: 1, y: 0, w: 3, h: 2 }}>
b
</div>
<div key="c" data-grid={{ x: 4, y: 0, w: 1, h: 2 }}>
c
</div>
</ReactGridLayout>
Responsive Usage
Use Responsive for automatic breakpoint handling:
import { Responsive, useContainerWidth } from "react-grid-layout";
function MyResponsiveGrid() {
const { width, containerRef, mounted } = useContainerWidth();
const layouts = {
lg: [{ i: "1", x: 0, y: 0, w: 2, h: 2 }],
md: [{ i: "1", x: 0, y: 0, w: 2, h: 2 }]
};
return (
<div ref={containerRef}>
{mounted && (
<Responsive
layouts={layouts}
breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }}
width={width}
>
<div key="1">1</div>
<div key="2">2</div>
<div key="3">3</div>
</Responsive>
)}
</div>
);
}
Providing Grid Width
The width prop is required. You have several options:
Option 1: useContainerWidth Hook (Recommended)
import ReactGridLayout, { useContainerWidth } from "react-grid-layout";
function MyGrid() {
const { width, containerRef, mounted } = useContainerWidth();
return (
<div ref={containerRef}>
{mounted && <ReactGridLayout width={width}>...</ReactGridLayout>}
</div>
);
}
Option 2: Fixed Width
<ReactGridLayout width={1200}>...</ReactGridLayout>
Option 3: CSS Container Queries or ResizeObserver
Use any width measurement library like react-sizeme or your own ResizeObserver implementation.
Option 4: Legacy WidthProvider HOC
For backwards compatibility, you can still use WidthProvider:
import ReactGridLayout, { WidthProvider } from "react-grid-layout/legacy";
const GridLayoutWithWidth = WidthProvider(ReactGridLayout);
function MyGrid() {
return <GridLayoutWithWidth>...</GridLayoutWithWidth>;
}
Hooks API
The v2 API provides three hooks for different use cases. Choose based on your needs:
useContainerWidth | You need responsive width measurement (most common) |
useGridLayout | You're building a custom grid component or need direct state control |
useResponsiveLayout | You're building a custom responsive grid with breakpoint logic |
useContainerWidth
Observes container width using ResizeObserver and provides reactive width updates. This is the recommended way to provide width to the grid.
Why use it instead of WidthProvider?
- Hooks are more composable and easier to test
- No HOC wrapper means simpler component tree
- Explicit control over when to render (via
mounted)
- Works better with SSR
import { useContainerWidth } from "react-grid-layout";
function MyGrid() {
const { width, containerRef, mounted, measureWidth } = useContainerWidth({
measureBeforeMount: false,
initialWidth: 1280
});
return (
<div ref={containerRef}>{mounted && <ReactGridLayout width={width} />}</div>
);
}
Type Definitions:
interface UseContainerWidthOptions {
measureBeforeMount?: boolean;
initialWidth?: number;
}
interface UseContainerWidthResult {
width: number;
mounted: boolean;
containerRef: RefObject<HTMLDivElement | null>;
measureWidth: () => void;
}
useGridLayout
Core layout state management hook. Use this when you need direct control over drag/resize/drop state, or when building a custom grid component.
Why use it instead of the component?
- Full control over layout state and updates
- Access to drag/resize/drop state for custom UIs
- Can integrate with external state management
- Build headless grid implementations
import { useGridLayout } from "react-grid-layout";
function CustomGrid({ initialLayout }) {
const {
layout,
setLayout,
dragState,
resizeState,
onDragStart,
onDrag,
onDragStop,
onResizeStart,
onResize,
onResizeStop,
containerHeight,
isInteracting,
compactor
} = useGridLayout({
layout: initialLayout,
cols: 12,
compactType: "vertical",
allowOverlap: false,
preventCollision: false,
onLayoutChange: newLayout => console.log("Layout changed:", newLayout)
});
const placeholder = dragState.activeDrag;
if (isInteracting) {
}
return (
<div style={{ height: containerHeight * rowHeight }}>
{layout.map(item => (
<div
key={item.i}
onMouseDown={() => onDragStart(item.i, item.x, item.y)}
>
{item.i}
</div>
))}
{placeholder && <div className="placeholder" />}
</div>
);
}
Type Definitions:
interface UseGridLayoutOptions {
layout: Layout;
cols: number;
compactType?: CompactType;
allowOverlap?: boolean;
preventCollision?: boolean;
onLayoutChange?: (layout: Layout) => void;
}
interface UseGridLayoutResult {
layout: Layout;
setLayout: (layout: Layout) => void;
dragState: DragState;
resizeState: ResizeState;
dropState: DropState;
onDragStart: (itemId: string, x: number, y: number) => LayoutItem | null;
onDrag: (itemId: string, x: number, y: number) => void;
onDragStop: (itemId: string, x: number, y: number) => void;
onResizeStart: (itemId: string) => LayoutItem | null;
onResize: (
itemId: string,
w: number,
h: number,
x?: number,
y?: number
) => void;
onResizeStop: (itemId: string, w: number, h: number) => void;
onDropDragOver: (
droppingItem: LayoutItem,
position: DroppingPosition
) => void;
onDropDragLeave: () => void;
onDrop: (droppingItem: LayoutItem) => void;
containerHeight: number;
isInteracting: boolean;
compactor: Compactor;
}
useResponsiveLayout
Manages responsive breakpoints and generates layouts for different screen sizes. Use this when building a custom responsive grid.
Why use it instead of the Responsive component?
- Direct access to current breakpoint
- Control over layout generation for new breakpoints
- Can update layouts for specific breakpoints
- Build custom breakpoint UIs
import { useContainerWidth, useResponsiveLayout } from "react-grid-layout";
function CustomResponsiveGrid() {
const { width, containerRef, mounted } = useContainerWidth();
const {
layout,
layouts,
breakpoint,
cols,
setLayoutForBreakpoint,
setLayouts,
sortedBreakpoints
} = useResponsiveLayout({
width,
breakpoints: { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 },
cols: { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 },
layouts: {
lg: [{ i: "1", x: 0, y: 0, w: 2, h: 2 }],
md: [{ i: "1", x: 0, y: 0, w: 3, h: 2 }]
},
compactType: "vertical",
onBreakpointChange: (bp, cols) =>
console.log(`Now at ${bp} (${cols} cols)`),
onLayoutChange: (layout, allLayouts) => saveToServer(allLayouts)
});
return (
<div ref={containerRef}>
<div>
Current breakpoint: {breakpoint} ({cols} columns)
</div>
{mounted && (
<GridLayout width={width} cols={cols} layout={layout}>
{/* children */}
</GridLayout>
)}
</div>
);
}
Type Definitions:
interface UseResponsiveLayoutOptions<B extends string = DefaultBreakpoints> {
width: number;
breakpoints?: Record<B, number>;
cols?: Record<B, number>;
layouts?: Partial<Record<B, Layout>>;
compactType?: "vertical" | "horizontal" | null;
onBreakpointChange?: (newBreakpoint: B, cols: number) => void;
onLayoutChange?: (layout: Layout, layouts: Record<B, Layout>) => void;
onWidthChange?: (
width: number,
margin: [number, number],
cols: number,
padding: [number, number] | null
) => void;
}
interface UseResponsiveLayoutResult<B extends string = DefaultBreakpoints> {
layout: Layout;
layouts: Partial<Record<B, Layout>>;
breakpoint: B;
cols: number;
setLayoutForBreakpoint: (breakpoint: B, layout: Layout) => void;
setLayouts: (layouts: Partial<Record<B, Layout>>) => void;
sortedBreakpoints: B[];
}
type DefaultBreakpoints = "lg" | "md" | "sm" | "xs" | "xxs";
API Reference
ReactGridLayout Props
The v2 API uses composable configuration interfaces for cleaner prop organization:
interface ReactGridLayoutProps {
children: React.ReactNode;
width: number;
gridConfig?: Partial<GridConfig>;
dragConfig?: Partial<DragConfig>;
resizeConfig?: Partial<ResizeConfig>;
dropConfig?: Partial<DropConfig>;
positionStrategy?: PositionStrategy;
compactor?: Compactor;
layout?: Layout;
droppingItem?: LayoutItem;
autoSize?: boolean;
className?: string;
style?: React.CSSProperties;
innerRef?: React.Ref<HTMLDivElement>;
onLayoutChange?: (layout: Layout) => void;
onDragStart?: EventCallback;
onDrag?: EventCallback;
onDragStop?: EventCallback;
onResizeStart?: EventCallback;
onResize?: EventCallback;
onResizeStop?: EventCallback;
onDrop?: (layout: Layout, item: LayoutItem | undefined, e: Event) => void;
onDropDragOver?: (e: DragEvent) => { w?: number; h?: number } | false | void;
}
GridConfig
Grid measurement configuration:
interface GridConfig {
cols: number;
rowHeight: number;
margin: [number, number];
containerPadding: [number, number] | null;
maxRows: number;
}
DragConfig
Drag behavior configuration:
interface DragConfig {
enabled: boolean;
bounded: boolean;
handle?: string;
cancel?: string;
threshold: number;
}
ResizeConfig
Resize behavior configuration:
interface ResizeConfig {
enabled: boolean;
handles: ResizeHandleAxis[];
handleComponent?: React.ReactNode | ((axis, ref) => React.ReactNode);
}
DropConfig
External drop configuration:
interface DropConfig {
enabled: boolean;
defaultItem: { w: number; h: number };
onDragOver?: (e: DragEvent) => { w?: number; h?: number } | false | void;
}
PositionStrategy
CSS positioning strategy. Built-in options:
import {
transformStrategy,
absoluteStrategy,
createScaledStrategy
} from "react-grid-layout/core";
<div style={{ transform: 'scale(0.5)' }}>
<ReactGridLayout positionStrategy={createScaledStrategy(0.5)} ... />
</div>
Compactor
Layout compaction strategy. Built-in options:
import {
verticalCompactor,
horizontalCompactor,
noCompactor,
getCompactor
} from "react-grid-layout/core";
ResponsiveGridLayout Props
Extends GridLayoutProps with responsive-specific props:
interface ResponsiveGridLayoutProps<B extends string = string> {
breakpoint?: B;
breakpoints?: Record<B, number>;
cols?: Record<B, number>;
layouts?: Record<B, Layout>;
margin?: [number, number] | Partial<Record<B, [number, number]>>;
containerPadding?:
| [number, number]
| Partial<Record<B, [number, number] | null>>
| null;
onBreakpointChange?: (newBreakpoint: B, cols: number) => void;
onLayoutChange?: (layout: Layout, layouts: Record<B, Layout>) => void;
onWidthChange?: (
width: number,
margin: [number, number],
cols: number,
padding: [number, number] | null
) => void;
}
Layout Item
interface LayoutItem {
i: string;
x: number;
y: number;
w: number;
h: number;
minW?: number;
maxW?: number;
minH?: number;
maxH?: number;
static?: boolean;
isDraggable?: boolean;
isResizable?: boolean;
isBounded?: boolean;
resizeHandles?: Array<"s" | "w" | "e" | "n" | "sw" | "nw" | "se" | "ne">;
}
Core Utilities
Import pure layout functions from react-grid-layout/core:
import {
compact,
moveElement,
collides,
getFirstCollision,
validateLayout
} from "react-grid-layout/core";
Extending: Custom Compactors & Position Strategies
Creating a Custom Compactor
Compactors control how items are arranged after drag/resize. Create your own for custom layouts like masonry, gravity, or shelf-packing.
The Compactor Interface:
interface Compactor {
type: "vertical" | "horizontal" | null | string;
allowOverlap: boolean;
preventCollision?: boolean;
compact(layout: Layout, cols: number): Layout;
onMove(
layout: Layout,
item: LayoutItem,
x: number,
y: number,
cols: number
): Layout;
}
Example: Gravity Compactor (items fall to bottom)
import { cloneLayout, cloneLayoutItem, getStatics, bottom } from "react-grid-layout/core";
const gravityCompactor: Compactor = {
type: "gravity",
allowOverlap: false,
compact(layout, cols) {
const statics = getStatics(layout);
const maxY = 100;
const out = [];
const sorted = [...layout].sort((a, b) => b.y - a.y);
for (const item of sorted) {
const l = cloneLayoutItem(item);
if (!l.static) {
while (l.y < maxY && !collides(l, statics)) {
l.y++;
}
l.y--;
}
out.push(l);
}
return out;
},
onMove(layout, item, x, y, cols) {
const newLayout = cloneLayout(layout);
const movedItem = newLayout.find(l => l.i === item.i);
if (movedItem) {
movedItem.x = x;
movedItem.y = y;
movedItem.moved = true;
}
return newLayout;
}
};
<GridLayout compactor={gravityCompactor} />
Example: Single Row Compactor (horizontal shelf)
const singleRowCompactor: Compactor = {
type: "shelf",
allowOverlap: false,
compact(layout, cols) {
let x = 0;
const out = [];
const sorted = [...layout].sort((a, b) => a.x - b.x);
for (const item of sorted) {
const l = cloneLayoutItem(item);
if (!l.static) {
l.x = x;
l.y = 0;
x += l.w;
if (x > cols) {
l.x = 0;
x = l.w;
}
}
out.push(l);
}
return out;
},
onMove(layout, item, x, y, cols) {
const newLayout = cloneLayout(layout);
const movedItem = newLayout.find(l => l.i === item.i);
if (movedItem) {
movedItem.x = x;
movedItem.y = 0;
movedItem.moved = true;
}
return newLayout;
}
};
Using Helper Functions:
The core module exports helpers for building compactors:
import {
resolveCompactionCollision,
compactItemVertical,
compactItemHorizontal,
getFirstCollision,
collides,
getStatics,
cloneLayout,
cloneLayoutItem
} from "react-grid-layout/core";
Creating a Custom Position Strategy
Position strategies control how items are positioned via CSS. Create custom strategies for special transform handling.
The PositionStrategy Interface:
interface PositionStrategy {
type: "transform" | "absolute" | string;
scale: number;
calcStyle(pos: Position): React.CSSProperties;
calcDragPosition(
clientX: number,
clientY: number,
offsetX: number,
offsetY: number
): { left: number; top: number };
}
Example: Rotated Container Strategy
const createRotatedStrategy = (angleDegrees: number): PositionStrategy => {
const angleRad = (angleDegrees * Math.PI) / 180;
const cos = Math.cos(angleRad);
const sin = Math.sin(angleRad);
return {
type: "rotated",
scale: 1,
calcStyle(pos) {
const rotatedX = pos.left * cos - pos.top * sin;
const rotatedY = pos.left * sin + pos.top * cos;
return {
transform: `translate(${rotatedX}px, ${rotatedY}px)`,
width: `${pos.width}px`,
height: `${pos.height}px`,
position: "absolute"
};
},
calcDragPosition(clientX, clientY, offsetX, offsetY) {
const x = clientX - offsetX;
const y = clientY - offsetY;
return {
left: x * cos + y * sin,
top: -x * sin + y * cos
};
}
};
};
<div style={{ transform: 'rotate(45deg)' }}>
<GridLayout positionStrategy={createRotatedStrategy(45)} />
</div>
Example: 3D Perspective Strategy
const create3DStrategy = (
perspective: number,
rotateX: number
): PositionStrategy => ({
type: "3d",
scale: 1,
calcStyle(pos) {
return {
transform: `
perspective(${perspective}px)
rotateX(${rotateX}deg)
translate3d(${pos.left}px, ${pos.top}px, 0)
`,
width: `${pos.width}px`,
height: `${pos.height}px`,
position: "absolute",
transformStyle: "preserve-3d"
};
},
calcDragPosition(clientX, clientY, offsetX, offsetY) {
const perspectiveFactor = 1 + clientY / perspective;
return {
left: (clientX - offsetX) / perspectiveFactor,
top: (clientY - offsetY) / perspectiveFactor
};
}
});
The react-grid-layout/extras entry point provides optional components that extend react-grid-layout. These are tree-shakeable and won't be included in your bundle unless explicitly imported.
GridBackground
Renders an SVG grid background that aligns with GridLayout cells. Use this to visualize the grid structure behind your layout.
Based on PR #2175 by @dmj900501.
import { GridBackground } from "react-grid-layout/extras";
import ReactGridLayout, { useContainerWidth } from "react-grid-layout";
function MyGrid() {
const { width, containerRef, mounted } = useContainerWidth();
return (
<div ref={containerRef} style={{ position: "relative" }}>
{mounted && (
<>
<GridBackground
width={width}
cols={12}
rowHeight={30}
margin={[10, 10]}
rows={10}
color="#f0f0f0"
borderRadius={4}
/>
<ReactGridLayout
width={width}
gridConfig={{ cols: 12, rowHeight: 30, margin: [10, 10] }}
>
{children}
</ReactGridLayout>
</>
)}
</div>
);
}
Props:
interface GridBackgroundProps {
width: number;
cols: number;
rowHeight: number;
margin?: [number, number];
containerPadding?: [number, number] | null;
rows?: number | "auto";
height?: number;
color?: string;
borderRadius?: number;
className?: string;
style?: React.CSSProperties;
}
Fast Compactors
For large layouts (200+ items), the standard compactors can become slow due to O(n²) collision resolution. The fast compactors use optimized algorithms with O(n log n) complexity.
Based on the "rising tide" algorithm from PR #2152 by @morris.
import {
fastVerticalCompactor,
fastHorizontalCompactor,
fastVerticalOverlapCompactor,
fastHorizontalOverlapCompactor
} from "react-grid-layout/extras";
<ReactGridLayout
compactor={fastVerticalCompactor}
// or compactor={fastHorizontalCompactor}
layout={layout}
width={width}
/>;
Performance Benchmarks:
| 50 | 112 µs | 19 µs | 6x |
| 100 | 203 µs | 36 µs | 6x |
| 200 | 821 µs | 51 µs | 16x |
| 500 | 5.7 ms | 129 µs | 45x |
| 50 | 164 µs | 12 µs | 14x |
| 100 | 477 µs | 25 µs | 19x |
| 200 | 1.1 ms | 42 µs | 26x |
| 500 | 9.5 ms | 128 µs | 74x |
Correctness:
The fast compactors produce layouts identical to the standard compactors:
- Vertical: 0% height difference on deterministic 100-item layouts
- Horizontal: 0% width difference on deterministic 100-item layouts
- Both pass all correctness tests: no overlaps, idempotent, static item handling
When to use:
- Use fast compactors for dashboards with 200+ widgets
- For smaller layouts (<100 items), standard compactors work equally well
- Both standard and fast compactors produce valid, non-overlapping layouts
calcGridCellDimensions (Core Utility)
For building custom grid overlays or backgrounds, use the calcGridCellDimensions utility from react-grid-layout/core:
import { calcGridCellDimensions } from "react-grid-layout/core";
const dims = calcGridCellDimensions({
width: 1200,
cols: 12,
rowHeight: 30,
margin: [10, 10],
containerPadding: [20, 20]
});
This is useful for building custom visualizations, snap-to-grid functionality, or integrating with canvas/WebGL renderers.
Performance
Memoize Children
The grid compares children by reference. Memoize them for better performance:
function MyGrid({ count, width }) {
const children = useMemo(() => {
return Array.from({ length: count }, (_, i) => (
<div
key={i}
data-grid={{ x: i % 12, y: Math.floor(i / 12), w: 1, h: 1 }}
/>
));
}, [count]);
return (
<ReactGridLayout width={width} gridConfig={{ cols: 12 }}>
{children}
</ReactGridLayout>
);
}
Avoid Creating Components in Render (Legacy WidthProvider)
If using the legacy WidthProvider HOC, don't create the component during render:
import ReactGridLayout, { WidthProvider } from "react-grid-layout/legacy";
function MyGrid() {
const GridLayoutWithWidth = WidthProvider(ReactGridLayout);
return <GridLayoutWithWidth>...</GridLayoutWithWidth>;
}
const GridLayoutWithWidth = WidthProvider(ReactGridLayout);
function MyGrid() {
return <GridLayoutWithWidth>...</GridLayoutWithWidth>;
}
With the v2 API, use useContainerWidth hook instead to avoid this issue entirely.
Custom Child Components
Grid children must forward refs and certain props:
const CustomItem = forwardRef<HTMLDivElement, CustomItemProps>(
(
{
style,
className,
onMouseDown,
onMouseUp,
onTouchEnd,
children,
...props
},
ref
) => {
return (
<div
ref={ref}
style={style}
className={className}
onMouseDown={onMouseDown}
onMouseUp={onMouseUp}
onTouchEnd={onTouchEnd}
>
{children}
</div>
);
}
);
Contribute
If you have a feature request, please add it as an issue or make a pull request.
If you have a bug to report, please reproduce the bug in CodeSandbox to help
us easily isolate it.