react-grid-layout 1.5.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +1074 -432
  2. package/css/styles.css +6 -4
  3. package/dist/ResponsiveGridLayout-CH4s0tKj.d.ts +124 -0
  4. package/dist/ResponsiveGridLayout-D6lFRE3f.d.mts +124 -0
  5. package/dist/calculate-CwYDW8na.d.mts +168 -0
  6. package/dist/calculate-mgLpNJ5O.d.ts +168 -0
  7. package/dist/chunk-2KUHNJXF.mjs +90 -0
  8. package/dist/chunk-2KUHNJXF.mjs.map +1 -0
  9. package/dist/chunk-3WO4SAYB.js +868 -0
  10. package/dist/chunk-3WO4SAYB.js.map +1 -0
  11. package/dist/chunk-4HNUMWQK.mjs +822 -0
  12. package/dist/chunk-4HNUMWQK.mjs.map +1 -0
  13. package/dist/chunk-BFTKGAP3.js +1309 -0
  14. package/dist/chunk-BFTKGAP3.js.map +1 -0
  15. package/dist/chunk-F6NQPYKT.js +98 -0
  16. package/dist/chunk-F6NQPYKT.js.map +1 -0
  17. package/dist/chunk-H5KMDLY3.js +434 -0
  18. package/dist/chunk-H5KMDLY3.js.map +1 -0
  19. package/dist/chunk-PBQSHIID.js +4 -0
  20. package/dist/chunk-PBQSHIID.js.map +1 -0
  21. package/dist/chunk-R35HZZTA.mjs +1300 -0
  22. package/dist/chunk-R35HZZTA.mjs.map +1 -0
  23. package/dist/chunk-ZCXE6SR5.mjs +428 -0
  24. package/dist/chunk-ZCXE6SR5.mjs.map +1 -0
  25. package/dist/chunk-ZWN22PS2.mjs +3 -0
  26. package/dist/chunk-ZWN22PS2.mjs.map +1 -0
  27. package/dist/core.d.mts +33 -0
  28. package/dist/core.d.ts +33 -0
  29. package/dist/core.js +218 -0
  30. package/dist/core.js.map +1 -0
  31. package/dist/core.mjs +5 -0
  32. package/dist/core.mjs.map +1 -0
  33. package/dist/extras.d.mts +78 -0
  34. package/dist/extras.d.ts +78 -0
  35. package/dist/extras.js +91 -0
  36. package/dist/extras.js.map +1 -0
  37. package/dist/extras.mjs +89 -0
  38. package/dist/extras.mjs.map +1 -0
  39. package/dist/index.d.mts +7 -0
  40. package/dist/index.d.ts +7 -0
  41. package/dist/index.js +154 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/index.mjs +7 -0
  44. package/dist/index.mjs.map +1 -0
  45. package/dist/legacy.d.mts +163 -0
  46. package/dist/legacy.d.ts +163 -0
  47. package/dist/legacy.js +319 -0
  48. package/dist/legacy.js.map +1 -0
  49. package/dist/legacy.mjs +307 -0
  50. package/dist/legacy.mjs.map +1 -0
  51. package/dist/position-BmN1z36J.d.mts +319 -0
  52. package/dist/position-Dk2b4ZMS.d.ts +319 -0
  53. package/dist/react.d.mts +351 -0
  54. package/dist/react.d.ts +351 -0
  55. package/dist/react.js +96 -0
  56. package/dist/react.js.map +1 -0
  57. package/dist/react.mjs +7 -0
  58. package/dist/react.mjs.map +1 -0
  59. package/dist/responsive-C4L1ESlm.d.ts +145 -0
  60. package/dist/responsive-CJxefsYw.d.mts +145 -0
  61. package/dist/types-Cxf4nHNr.d.mts +375 -0
  62. package/dist/types-Cxf4nHNr.d.ts +375 -0
  63. package/index-dev.js +8 -0
  64. package/package.json +132 -40
  65. package/.babelrc.js +0 -22
  66. package/.browserslistrc +0 -3
  67. package/.eslintignore +0 -4
  68. package/.flowconfig +0 -20
  69. package/.prettierignore +0 -4
  70. package/.prettierrc +0 -17
  71. package/CHANGELOG.md +0 -985
  72. package/build/GridItem.js +0 -638
  73. package/build/ReactGridLayout.js +0 -741
  74. package/build/ReactGridLayoutPropTypes.js +0 -210
  75. package/build/ResponsiveReactGridLayout.js +0 -297
  76. package/build/calculateUtils.js +0 -165
  77. package/build/components/WidthProvider.js +0 -115
  78. package/build/fastRGLPropsEqual.js +0 -5
  79. package/build/responsiveUtils.js +0 -101
  80. package/build/utils.js +0 -842
  81. package/dist/react-grid-layout.min.js +0 -2
  82. package/dist/react-grid-layout.min.js.map +0 -1
  83. package/index.js.flow +0 -8
  84. package/ip_fetcher +0 -0
  85. package/ip_fetcher.c +0 -47
  86. package/lib/GridItem.jsx +0 -689
  87. package/lib/ReactGridLayout.jsx +0 -855
  88. package/lib/ReactGridLayoutPropTypes.js +0 -241
  89. package/lib/ResponsiveReactGridLayout.jsx +0 -349
  90. package/lib/calculateUtils.js +0 -169
  91. package/lib/components/WidthProvider.jsx +0 -110
  92. package/lib/fastRGLPropsEqual.js +0 -46
  93. package/lib/responsiveUtils.js +0 -118
  94. package/lib/utils.js +0 -995
  95. package/yarn-error.log +0 -7780
package/README.md CHANGED
@@ -1,7 +1,5 @@
1
1
  # React-Grid-Layout
2
2
 
3
- [![travis build](https://travis-ci.org/STRML/react-grid-layout.svg?branch=master)](https://travis-ci.org/STRML/react-grid-layout)
4
- [![CDNJS](https://img.shields.io/cdnjs/v/react-grid-layout.svg)](https://cdnjs.com/libraries/react-grid-layout)
5
3
  [![npm package](https://img.shields.io/npm/v/react-grid-layout.svg?style=flat-square)](https://www.npmjs.org/package/react-grid-layout)
6
4
  [![npm downloads](https://img.shields.io/npm/dt/react-grid-layout.svg?maxAge=2592000)]()
7
5
 
@@ -21,19 +19,97 @@ RGL is React-only and does not require jQuery.
21
19
 
22
20
  ## Table of Contents
23
21
 
22
+ - [What's New in v2](#whats-new-in-v2)
23
+ - [Migrating from v1](#migrating-from-v1)
24
24
  - [Demos](#demos)
25
25
  - [Features](#features)
26
26
  - [Installation](#installation)
27
- - [Usage](#usage)
27
+ - [Quick Start](#quick-start)
28
28
  - [Responsive Usage](#responsive-usage)
29
29
  - [Providing Grid Width](#providing-grid-width)
30
- - [Grid Layout Props](#grid-layout-props)
31
- - [Responsive Grid Layout Props](#responsive-grid-layout-props)
32
- - [Grid Item Props](#grid-item-props)
33
- - [User Recipes](../../wiki/Users-recipes)
30
+ - [Hooks API](#hooks-api)
31
+ - [API Reference](#api-reference)
32
+ - [Extending: Custom Compactors & Position Strategies](#extending-custom-compactors--position-strategies)
33
+ - [Extras](#extras)
34
34
  - [Performance](#performance)
35
35
  - [Contribute](#contribute)
36
- - [TODO List](#todo-list)
36
+
37
+ ## What's New in v2
38
+
39
+ Version 2 is a complete TypeScript rewrite with a modernized API:
40
+
41
+ - **Full TypeScript support** - First-class types, no more `@types/react-grid-layout`
42
+ - **React Hooks** - New `useContainerWidth`, `useGridLayout`, and `useResponsiveLayout` hooks
43
+ - **Composable Configuration** - Group related props into focused interfaces:
44
+ - `gridConfig` - cols, rowHeight, margin, padding
45
+ - `dragConfig` - enable, handle, cancel, bounded
46
+ - `resizeConfig` - enable, handles
47
+ - `positionStrategy` - transform vs absolute positioning
48
+ - `compactor` - vertical, horizontal, or custom algorithms
49
+ - **Modular architecture** - Import only what you need:
50
+ - `react-grid-layout` - React components and hooks (v2 API)
51
+ - `react-grid-layout/core` - Pure layout algorithms (framework-agnostic)
52
+ - `react-grid-layout/legacy` - v1 flat props API for migration
53
+ - `react-grid-layout/extras` - Optional components like `GridBackground`
54
+ - **Smaller bundle** - Tree-shakeable ESM and CJS builds
55
+
56
+ ### Breaking Changes
57
+
58
+ See the [RFC](./rfcs/0001-v2-typescript-rewrite.md#breaking-changes-in-v2) for detailed migration examples.
59
+
60
+ | Change | Description |
61
+ | -------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
62
+ | [`width` prop required](./rfcs/0001-v2-typescript-rewrite.md#breaking-changes-in-v2) | Use `useContainerWidth` hook or provide your own measurement |
63
+ | [`onDragStart` threshold](./rfcs/0001-v2-typescript-rewrite.md#1-ondragstart-no-longer-fires-on-click-only-events) | Now fires after 3px movement, not on mousedown. Use `onMouseDown` for immediate response |
64
+ | [Immutable callbacks](./rfcs/0001-v2-typescript-rewrite.md#2-immutable-callback-parameters) | Callback parameters are read-only. Use `onLayoutChange` or constraints instead of mutation |
65
+ | [`data-grid` in legacy only](./rfcs/0001-v2-typescript-rewrite.md#3-data-grid-prop-only-available-in-legacy-wrapper) | v2 requires explicit `layout` prop. Use legacy wrapper for `data-grid` |
66
+ | [Fast compaction](./rfcs/0001-v2-typescript-rewrite.md#4-fast-compaction-algorithm-by-default) | O(n log n) algorithm may differ in edge cases. Use `compact()` from `/core` for exact v1 behavior |
67
+ | UMD bundle removed | Use a bundler (Vite, webpack, esbuild) |
68
+ | `verticalCompact` removed | Use `compactType={null}` or `compactor={noCompactor}` |
69
+
70
+ ## Migrating from v1
71
+
72
+ **Quick migration** - change your import to use the legacy wrapper:
73
+
74
+ ```diff
75
+ - import GridLayout, { Responsive, WidthProvider } from 'react-grid-layout';
76
+ + import GridLayout, { Responsive, WidthProvider } from 'react-grid-layout/legacy';
77
+ ```
78
+
79
+ This provides **100% API compatibility** with v1.
80
+
81
+ **Full migration** - adopt the v2 API for new features and better tree-shaking:
82
+
83
+ ```typescript
84
+ import ReactGridLayout, { useContainerWidth, verticalCompactor } from 'react-grid-layout';
85
+
86
+ function MyGrid() {
87
+ const { width, containerRef, mounted } = useContainerWidth();
88
+
89
+ return (
90
+ <div ref={containerRef}>
91
+ {mounted && (
92
+ <ReactGridLayout
93
+ width={width}
94
+ layout={layout}
95
+ gridConfig={{ cols: 12, rowHeight: 30 }}
96
+ dragConfig={{ enabled: true, handle: '.handle' }}
97
+ compactor={verticalCompactor}
98
+ >
99
+ {children}
100
+ </ReactGridLayout>
101
+ )}
102
+ </div>
103
+ );
104
+ }
105
+ ```
106
+
107
+ | Use Case | Recommendation |
108
+ | -------------------- | ---------------------------------- |
109
+ | Existing v1 codebase | `react-grid-layout/legacy` |
110
+ | New project | v2 API with hooks |
111
+ | Custom compaction | v2 with custom `Compactor` |
112
+ | SSR | v2 with `measureBeforeMount: true` |
37
113
 
38
114
  ## Demos
39
115
 
@@ -68,25 +144,15 @@ RGL is React-only and does not require jQuery.
68
144
  - [Grafana](https://grafana.com/)
69
145
  - [Metabase](http://www.metabase.com/)
70
146
  - [HubSpot](http://www.hubspot.com)
71
- - [ComNetViz](http://www.grotto-networking.com/ComNetViz/ComNetViz.html)
72
- - [Stoplight](https://app.stoplight.io)
73
- - [Reflect](https://reflect.io)
74
- - [ez-Dashing](https://github.com/ylacaute/ez-Dashing)
75
147
  - [Kibana](https://www.elastic.co/products/kibana)
76
- - [Graphext](https://graphext.com/)
77
148
  - [Monday](https://support.monday.com/hc/en-us/articles/360002187819-What-are-the-Dashboards-)
78
- - [Quadency](https://quadency.com/)
79
- - [Hakkiri](https://www.hakkiri.io)
80
- - [Ubidots](https://help.ubidots.com/en/articles/2400308-create-dashboards-and-widgets)
81
- - [Statsout](https://statsout.com/)
82
- - [Datto RMM](https://www.datto.com/uk/products/rmm/)
83
- - [SquaredUp](https://squaredup.com/)
84
149
 
85
150
  _Know of others? Create a PR to let me know!_
86
151
 
87
152
  ## Features
88
153
 
89
154
  - 100% React - no jQuery
155
+ - Full TypeScript support
90
156
  - Compatible with server-rendered apps
91
157
  - Draggable widgets
92
158
  - Resizable widgets
@@ -98,506 +164,1098 @@ _Know of others? Create a PR to let me know!_
98
164
  - Responsive breakpoints
99
165
  - Separate layouts per responsive breakpoint
100
166
  - Grid Items placed using CSS Transforms
101
- - Performance with CSS Transforms: [on](http://i.imgur.com/FTogpLp.jpg) / [off](http://i.imgur.com/gOveMm8.jpg), note paint (green) as % of time
102
167
  - Compatibility with `<React.StrictMode>`
103
168
 
104
- | Version | Compatibility |
105
- | ------------ | --------------- |
106
- | >= 0.17.0 | React 16 & 17 |
107
- | >= 0.11.3 | React 0.14 & 15 |
108
- | >= 0.10.0 | React 0.14 |
109
- | 0.8. - 0.9.2 | React 0.13 |
110
- | < 0.8 | React 0.12 |
169
+ | Version | Compatibility |
170
+ | --------- | --------------------- |
171
+ | >= 2.0.0 | React 18+, TypeScript |
172
+ | >= 0.17.0 | React 16 & 17 |
111
173
 
112
174
  ## Installation
113
175
 
114
- Install the React-Grid-Layout [package](https://www.npmjs.org/package/react-grid-layout) using [npm](https://www.npmjs.com/):
115
-
116
176
  ```bash
117
177
  npm install react-grid-layout
118
178
  ```
119
179
 
120
- Include the following stylesheets in your application:
180
+ Include the stylesheets in your application:
121
181
 
182
+ ```js
183
+ import "react-grid-layout/css/styles.css";
184
+ import "react-resizable/css/styles.css";
122
185
  ```
123
- /node_modules/react-grid-layout/css/styles.css
124
- /node_modules/react-resizable/css/styles.css
186
+
187
+ Or link them directly:
188
+
189
+ ```html
190
+ <link rel="stylesheet" href="/node_modules/react-grid-layout/css/styles.css" />
191
+ <link rel="stylesheet" href="/node_modules/react-resizable/css/styles.css" />
125
192
  ```
126
193
 
127
- ## Usage
194
+ ## Quick Start
128
195
 
129
- Use ReactGridLayout like any other component. The following example below will
130
- produce a grid with three items where:
196
+ ```tsx
197
+ import ReactGridLayout, { useContainerWidth } from "react-grid-layout";
198
+ import "react-grid-layout/css/styles.css";
199
+ import "react-resizable/css/styles.css";
131
200
 
132
- - users will not be able to drag or resize item `a`
133
- - item `b` will be restricted to a minimum width of 2 grid blocks and a maximum width of 4 grid blocks
134
- - users will be able to freely drag and resize item `c`
201
+ function MyGrid() {
202
+ const { width, containerRef, mounted } = useContainerWidth();
135
203
 
136
- ```js
137
- import GridLayout from "react-grid-layout";
138
-
139
- class MyFirstGrid extends React.Component {
140
- render() {
141
- // layout is an array of objects, see the demo for more complete usage
142
- const layout = [
143
- { i: "a", x: 0, y: 0, w: 1, h: 2, static: true },
144
- { i: "b", x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4 },
145
- { i: "c", x: 4, y: 0, w: 1, h: 2 }
146
- ];
147
- return (
148
- <GridLayout
149
- className="layout"
150
- layout={layout}
151
- cols={12}
152
- rowHeight={30}
153
- width={1200}
154
- >
155
- <div key="a">a</div>
156
- <div key="b">b</div>
157
- <div key="c">c</div>
158
- </GridLayout>
159
- );
160
- }
204
+ const layout = [
205
+ { i: "a", x: 0, y: 0, w: 1, h: 2, static: true },
206
+ { i: "b", x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4 },
207
+ { i: "c", x: 4, y: 0, w: 1, h: 2 }
208
+ ];
209
+
210
+ return (
211
+ <div ref={containerRef}>
212
+ {mounted && (
213
+ <ReactGridLayout
214
+ layout={layout}
215
+ width={width}
216
+ gridConfig={{ cols: 12, rowHeight: 30 }}
217
+ >
218
+ <div key="a">a</div>
219
+ <div key="b">b</div>
220
+ <div key="c">c</div>
221
+ </ReactGridLayout>
222
+ )}
223
+ </div>
224
+ );
161
225
  }
162
226
  ```
163
227
 
164
- You may also choose to set layout properties directly on the children:
228
+ You can also define layout on children using `data-grid`:
229
+
230
+ ```tsx
231
+ <ReactGridLayout width={width} gridConfig={{ cols: 12, rowHeight: 30 }}>
232
+ <div key="a" data-grid={{ x: 0, y: 0, w: 1, h: 2, static: true }}>
233
+ a
234
+ </div>
235
+ <div key="b" data-grid={{ x: 1, y: 0, w: 3, h: 2 }}>
236
+ b
237
+ </div>
238
+ <div key="c" data-grid={{ x: 4, y: 0, w: 1, h: 2 }}>
239
+ c
240
+ </div>
241
+ </ReactGridLayout>
242
+ ```
165
243
 
166
- ```js
167
- import GridLayout from "react-grid-layout";
244
+ ## Responsive Usage
168
245
 
169
- class MyFirstGrid extends React.Component {
170
- render() {
171
- return (
172
- <GridLayout className="layout" cols={12} rowHeight={30} width={1200}>
173
- <div key="a" data-grid={{ x: 0, y: 0, w: 1, h: 2, static: true }}>
174
- a
175
- </div>
176
- <div key="b" data-grid={{ x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4 }}>
177
- b
178
- </div>
179
- <div key="c" data-grid={{ x: 4, y: 0, w: 1, h: 2 }}>
180
- c
181
- </div>
182
- </GridLayout>
183
- );
184
- }
246
+ Use `Responsive` for automatic breakpoint handling:
247
+
248
+ ```tsx
249
+ import { Responsive, useContainerWidth } from "react-grid-layout";
250
+
251
+ function MyResponsiveGrid() {
252
+ const { width, containerRef, mounted } = useContainerWidth();
253
+
254
+ const layouts = {
255
+ lg: [{ i: "1", x: 0, y: 0, w: 2, h: 2 }],
256
+ md: [{ i: "1", x: 0, y: 0, w: 2, h: 2 }]
257
+ };
258
+
259
+ return (
260
+ <div ref={containerRef}>
261
+ {mounted && (
262
+ <Responsive
263
+ layouts={layouts}
264
+ breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
265
+ cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }}
266
+ width={width}
267
+ >
268
+ <div key="1">1</div>
269
+ <div key="2">2</div>
270
+ <div key="3">3</div>
271
+ </Responsive>
272
+ )}
273
+ </div>
274
+ );
185
275
  }
186
276
  ```
187
277
 
188
- ### Usage without Browserify/Webpack
278
+ ## Providing Grid Width
189
279
 
190
- A module usable in a `<script>` tag is included [here](/dist/react-grid-layout.min.js). It uses a UMD shim and
191
- excludes `React`, so it must be otherwise available in your application, either via RequireJS or on `window.React`.
280
+ The `width` prop is required. You have several options:
192
281
 
193
- ### Responsive Usage
282
+ ### Option 1: useContainerWidth Hook (Recommended)
194
283
 
195
- To make RGL responsive, use the `<ResponsiveReactGridLayout>` element:
284
+ ```tsx
285
+ import ReactGridLayout, { useContainerWidth } from "react-grid-layout";
196
286
 
197
- ```js
198
- import { Responsive as ResponsiveGridLayout } from "react-grid-layout";
287
+ function MyGrid() {
288
+ const { width, containerRef, mounted } = useContainerWidth();
199
289
 
200
- class MyResponsiveGrid extends React.Component {
201
- render() {
202
- // {lg: layout1, md: layout2, ...}
203
- const layouts = getLayoutsFromSomewhere();
204
- return (
205
- <ResponsiveGridLayout
206
- className="layout"
207
- layouts={layouts}
208
- breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
209
- cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }}
210
- >
211
- <div key="1">1</div>
212
- <div key="2">2</div>
213
- <div key="3">3</div>
214
- </ResponsiveGridLayout>
215
- );
216
- }
290
+ return (
291
+ <div ref={containerRef}>
292
+ {mounted && <ReactGridLayout width={width}>...</ReactGridLayout>}
293
+ </div>
294
+ );
217
295
  }
218
296
  ```
219
297
 
220
- When in responsive mode, you should supply at least one breakpoint via the `layouts` property.
298
+ ### Option 2: Fixed Width
221
299
 
222
- When using `layouts`, it is best to supply as many breakpoints as possible, especially the largest one.
223
- If the largest is provided, RGL will attempt to interpolate the rest.
300
+ ```tsx
301
+ <ReactGridLayout width={1200}>...</ReactGridLayout>
302
+ ```
224
303
 
225
- You will also need to provide a `width`, when using `<ResponsiveReactGridLayout>` it is suggested you use the HOC
226
- `WidthProvider` as per the instructions below.
304
+ ### Option 3: CSS Container Queries or ResizeObserver
227
305
 
228
- It is possible to supply default mappings via the `data-grid` property on individual
229
- items, so that they would be taken into account within layout interpolation.
306
+ Use any width measurement library like [react-sizeme](https://github.com/ctrlplusb/react-sizeme) or your own ResizeObserver implementation.
230
307
 
231
- ### Providing Grid Width
308
+ ### Option 4: Legacy WidthProvider HOC
232
309
 
233
- Both `<ResponsiveReactGridLayout>` and `<ReactGridLayout>` take `width` to calculate
234
- positions on drag events. In simple cases a HOC `WidthProvider` can be used to automatically determine
235
- width upon initialization and window resize events.
310
+ For backwards compatibility, you can still use `WidthProvider`:
236
311
 
237
- ```js
238
- import { Responsive, WidthProvider } from "react-grid-layout";
312
+ ```tsx
313
+ import ReactGridLayout, { WidthProvider } from "react-grid-layout/legacy";
239
314
 
240
- const ResponsiveGridLayout = WidthProvider(Responsive);
315
+ const GridLayoutWithWidth = WidthProvider(ReactGridLayout);
241
316
 
242
- class MyResponsiveGrid extends React.Component {
243
- render() {
244
- // {lg: layout1, md: layout2, ...}
245
- var layouts = getLayoutsFromSomewhere();
246
- return (
247
- <ResponsiveGridLayout
248
- className="layout"
249
- layouts={layouts}
250
- breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
251
- cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }}
252
- >
253
- <div key="1">1</div>
254
- <div key="2">2</div>
255
- <div key="3">3</div>
256
- </ResponsiveGridLayout>
257
- );
258
- }
317
+ function MyGrid() {
318
+ return <GridLayoutWithWidth>...</GridLayoutWithWidth>;
259
319
  }
260
320
  ```
261
321
 
262
- This allows you to easily replace `WidthProvider` with your own Provider HOC if you need more sophisticated logic.
322
+ ## Hooks API
263
323
 
264
- `WidthProvider` accepts a single prop, `measureBeforeMount`. If `true`, `WidthProvider` will measure the
265
- container's width before mounting children. Use this if you'd like to completely eliminate any resizing animation
266
- on application/component mount.
324
+ The v2 API provides three hooks for different use cases. Choose based on your needs:
267
325
 
268
- Have a more complicated layout? `WidthProvider` [is very simple](/lib/components/WidthProvider.jsx) and only
269
- listens to window `'resize'` events. If you need more power and flexibility, try the
270
- [SizeMe React HOC](https://github.com/ctrlplusb/react-sizeme) as an alternative to WidthProvider.
326
+ | Hook | Use When |
327
+ | --------------------- | -------------------------------------------------------------------- |
328
+ | `useContainerWidth` | You need responsive width measurement (most common) |
329
+ | `useGridLayout` | You're building a custom grid component or need direct state control |
330
+ | `useResponsiveLayout` | You're building a custom responsive grid with breakpoint logic |
271
331
 
272
- ### Grid Layout Props
332
+ ### useContainerWidth
273
333
 
274
- RGL supports the following properties (see the source for the final word on this):
334
+ Observes container width using ResizeObserver and provides reactive width updates. This is the recommended way to provide width to the grid.
275
335
 
276
- ```js
277
- //
278
- // Basic props
279
- //
280
-
281
- // This allows setting the initial width on the server side.
282
- // This is required unless using the HOC <WidthProvider> or similar
283
- width: number,
284
-
285
- // If true, the container height swells and contracts to fit contents
286
- autoSize: ?boolean = true,
287
-
288
- // Number of columns in this layout.
289
- cols: ?number = 12,
290
-
291
- // A CSS selector for tags that will not be draggable.
292
- // For example: draggableCancel:'.MyNonDraggableAreaClassName'
293
- // If you forget the leading . it will not work.
294
- // .react-resizable-handle" is always prepended to this value.
295
- draggableCancel: ?string = '',
296
-
297
- // A CSS selector for tags that will act as the draggable handle.
298
- // For example: draggableHandle:'.MyDragHandleClassName'
299
- // If you forget the leading . it will not work.
300
- draggableHandle: ?string = '',
301
-
302
- // Compaction type.
303
- compactType: ?('vertical' | 'horizontal' | null) = 'vertical';
304
-
305
- // Layout is an array of objects with the format:
306
- // The index into the layout must match the key used on each item component.
307
- // If you choose to use custom keys, you can specify that key in the layout
308
- // array objects using the `i` prop.
309
- layout: ?Array<{i?: string, x: number, y: number, w: number, h: number}> = null, // If not provided, use data-grid props on children
310
-
311
- // Margin between items [x, y] in px.
312
- margin: ?[number, number] = [10, 10],
313
-
314
- // Padding inside the container [x, y] in px
315
- containerPadding: ?[number, number] = margin,
316
-
317
- // Rows have a static height, but you can change this based on breakpoints
318
- // if you like.
319
- rowHeight: ?number = 150,
320
-
321
- // Configuration of a dropping element. Dropping element is a "virtual" element
322
- // which appears when you drag over some element from outside.
323
- // It can be changed by passing specific parameters:
324
- // i - id of an element
325
- // w - width of an element
326
- // h - height of an element
327
- droppingItem?: { i: string, w: number, h: number }
328
-
329
- //
330
- // Flags
331
- //
332
- isDraggable: ?boolean = true,
333
- isResizable: ?boolean = true,
334
- isBounded: ?boolean = false,
335
- // Uses CSS3 translate() instead of position top/left.
336
- // This makes about 6x faster paint performance
337
- useCSSTransforms: ?boolean = true,
338
- // If parent DOM node of ResponsiveReactGridLayout or ReactGridLayout has "transform: scale(n)" css property,
339
- // we should set scale coefficient to avoid render artefacts while dragging.
340
- transformScale: ?number = 1,
341
-
342
- // If true, grid can be placed one over the other.
343
- // If set, implies `preventCollision`.
344
- allowOverlap: ?boolean = false,
345
-
346
- // If true, grid items won't change position when being
347
- // dragged over. If `allowOverlap` is still false,
348
- // this simply won't allow one to drop on an existing object.
349
- preventCollision: ?boolean = false,
350
-
351
- // If true, droppable elements (with `draggable={true}` attribute)
352
- // can be dropped on the grid. It triggers "onDrop" callback
353
- // with position and event object as parameters.
354
- // It can be useful for dropping an element in a specific position
355
- //
356
- // NOTE: In case of using Firefox you should add
357
- // `onDragStart={e => e.dataTransfer.setData('text/plain', '')}` attribute
358
- // along with `draggable={true}` otherwise this feature will work incorrect.
359
- // onDragStart attribute is required for Firefox for a dragging initialization
360
- // @see https://bugzilla.mozilla.org/show_bug.cgi?id=568313
361
- isDroppable: ?boolean = false,
362
- // Defines which resize handles should be rendered.
363
- // Allows for any combination of:
364
- // 's' - South handle (bottom-center)
365
- // 'w' - West handle (left-center)
366
- // 'e' - East handle (right-center)
367
- // 'n' - North handle (top-center)
368
- // 'sw' - Southwest handle (bottom-left)
369
- // 'nw' - Northwest handle (top-left)
370
- // 'se' - Southeast handle (bottom-right)
371
- // 'ne' - Northeast handle (top-right)
372
- //
373
- // Note that changing this property dynamically does not work due to a restriction in react-resizable.
374
- resizeHandles: ?Array<'s' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne'> = ['se'],
375
- // Custom component for resize handles
376
- // See `handle` as used in https://github.com/react-grid-layout/react-resizable#resize-handle
377
- // Your component should have the class `.react-resizable-handle`, or you should add your custom
378
- // class to the `draggableCancel` prop.
379
- resizeHandle?: ReactElement<any> | ((resizeHandleAxis: ResizeHandleAxis, ref: ReactRef<HTMLElement>) => ReactElement<any>),
380
-
381
- //
382
- // Callbacks
383
- //
384
-
385
- // Callback so you can save the layout.
386
- // Calls back with (currentLayout) after every drag or resize stop.
387
- onLayoutChange: (layout: Layout) => void,
388
-
389
- //
390
- // All callbacks below have signature (layout, oldItem, newItem, placeholder, e, element).
391
- // 'start' and 'stop' callbacks pass `undefined` for 'placeholder'.
392
- //
393
- type ItemCallback = (layout: Layout, oldItem: LayoutItem, newItem: LayoutItem,
394
- placeholder: LayoutItem, e: MouseEvent, element: HTMLElement) => void,
395
-
396
- // Calls when drag starts.
397
- onDragStart: ItemCallback,
398
- // Calls on each drag movement.
399
- onDrag: ItemCallback,
400
- // Calls when drag is complete.
401
- onDragStop: ItemCallback,
402
- // Calls when resize starts.
403
- onResizeStart: ItemCallback,
404
- // Calls when resize movement happens.
405
- onResize: ItemCallback,
406
- // Calls when resize is complete.
407
- onResizeStop: ItemCallback,
408
-
409
- //
410
- // Dropover functionality
411
- //
412
-
413
- // Calls when an element has been dropped into the grid from outside.
414
- onDrop: (layout: Layout, item: ?LayoutItem, e: Event) => void,
415
- // Calls when an element is being dragged over the grid from outside as above.
416
- // This callback should return an object to dynamically change the droppingItem size
417
- // Return false to short-circuit the dragover
418
- onDropDragOver: (e: DragOverEvent) => ?({|w?: number, h?: number|} | false),
419
-
420
- // Ref for getting a reference for the grid's wrapping div.
421
- // You can use this instead of a regular ref and the deprecated `ReactDOM.findDOMNode()`` function.
422
- // Note that this type is React.Ref<HTMLDivElement> in TypeScript, Flow has a bug here
423
- // https://github.com/facebook/flow/issues/8671#issuecomment-862634865
424
- innerRef: {current: null | HTMLDivElement},
425
- ```
426
-
427
- ### Responsive Grid Layout Props
428
-
429
- The responsive grid layout can be used instead. It supports all of the props above, excepting `layout`.
430
- The new properties and changes are:
336
+ **Why use it instead of WidthProvider?**
431
337
 
432
- ```js
433
- // {name: pxVal}, e.g. {lg: 1200, md: 996, sm: 768, xs: 480}
434
- // Breakpoint names are arbitrary but must match in the cols and layouts objects.
435
- breakpoints: ?Object = {lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0},
338
+ - Hooks are more composable and easier to test
339
+ - No HOC wrapper means simpler component tree
340
+ - Explicit control over when to render (via `mounted`)
341
+ - Works better with SSR
436
342
 
437
- // # of cols. This is a breakpoint -> cols map, e.g. {lg: 12, md: 10, ...}
438
- cols: ?Object = {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2},
343
+ ```tsx
344
+ import { useContainerWidth } from "react-grid-layout";
439
345
 
346
+ function MyGrid() {
347
+ const { width, containerRef, mounted, measureWidth } = useContainerWidth({
348
+ measureBeforeMount: false, // Set true for SSR
349
+ initialWidth: 1280 // Width before first measurement
350
+ });
440
351
 
441
- // margin (in pixels). Can be specified either as horizontal and vertical margin, e.g. `[10, 10]` or as a breakpoint -> margin map, e.g. `{lg: [10, 10], md: [10, 10], ...}.
442
- margin: [number, number] | {[breakpoint: $Keys<breakpoints>]: [number, number]},
352
+ return (
353
+ <div ref={containerRef}>{mounted && <ReactGridLayout width={width} />}</div>
354
+ );
355
+ }
356
+ ```
443
357
 
358
+ **Type Definitions:**
444
359
 
445
- // containerPadding (in pixels). Can be specified either as horizontal and vertical padding, e.g. `[10, 10]` or as a breakpoint -> containerPadding map, e.g. `{lg: [10, 10], md: [10, 10], ...}.
446
- containerPadding: [number, number] | {[breakpoint: $Keys<breakpoints>]: [number, number]},
360
+ ```ts
361
+ interface UseContainerWidthOptions {
362
+ /** Delay render until width is measured. Useful for SSR. Default: false */
363
+ measureBeforeMount?: boolean;
364
+ /** Initial width before measurement. Default: 1280 */
365
+ initialWidth?: number;
366
+ }
447
367
 
368
+ interface UseContainerWidthResult {
369
+ /** Current container width in pixels */
370
+ width: number;
371
+ /** Whether the container has been measured at least once */
372
+ mounted: boolean;
373
+ /** Ref to attach to the container element */
374
+ containerRef: RefObject<HTMLDivElement | null>;
375
+ /** Manually trigger a width measurement */
376
+ measureWidth: () => void;
377
+ }
378
+ ```
448
379
 
449
- // layouts is an object mapping breakpoints to layouts.
450
- // e.g. {lg: Layout, md: Layout, ...}
451
- layouts: {[key: $Keys<breakpoints>]: Layout},
380
+ ### useGridLayout
381
+
382
+ Core layout state management hook. Use this when you need direct control over drag/resize/drop state, or when building a custom grid component.
383
+
384
+ **Why use it instead of the component?**
385
+
386
+ - Full control over layout state and updates
387
+ - Access to drag/resize/drop state for custom UIs
388
+ - Can integrate with external state management
389
+ - Build headless grid implementations
390
+
391
+ ```tsx
392
+ import { useGridLayout } from "react-grid-layout";
393
+
394
+ function CustomGrid({ initialLayout }) {
395
+ const {
396
+ layout,
397
+ setLayout,
398
+ dragState,
399
+ resizeState,
400
+ onDragStart,
401
+ onDrag,
402
+ onDragStop,
403
+ onResizeStart,
404
+ onResize,
405
+ onResizeStop,
406
+ containerHeight,
407
+ isInteracting,
408
+ compactor
409
+ } = useGridLayout({
410
+ layout: initialLayout,
411
+ cols: 12,
412
+ compactType: "vertical",
413
+ allowOverlap: false,
414
+ preventCollision: false,
415
+ onLayoutChange: newLayout => console.log("Layout changed:", newLayout)
416
+ });
417
+
418
+ // Access drag state for custom placeholder rendering
419
+ const placeholder = dragState.activeDrag;
420
+
421
+ // Check if any interaction is happening
422
+ if (isInteracting) {
423
+ // Disable other UI during drag/resize
424
+ }
452
425
 
453
- //
454
- // Callbacks
455
- //
426
+ return (
427
+ <div style={{ height: containerHeight * rowHeight }}>
428
+ {layout.map(item => (
429
+ <div
430
+ key={item.i}
431
+ onMouseDown={() => onDragStart(item.i, item.x, item.y)}
432
+ >
433
+ {item.i}
434
+ </div>
435
+ ))}
436
+ {placeholder && <div className="placeholder" />}
437
+ </div>
438
+ );
439
+ }
440
+ ```
456
441
 
457
- // Calls back with breakpoint and new # cols
458
- onBreakpointChange: (newBreakpoint: string, newCols: number) => void,
442
+ **Type Definitions:**
443
+
444
+ ```ts
445
+ interface UseGridLayoutOptions {
446
+ /** Initial layout */
447
+ layout: Layout;
448
+ /** Number of columns */
449
+ cols: number;
450
+ /** Compaction type: 'vertical', 'horizontal', or null */
451
+ compactType?: CompactType;
452
+ /** Allow items to overlap */
453
+ allowOverlap?: boolean;
454
+ /** Prevent collisions when moving items */
455
+ preventCollision?: boolean;
456
+ /** Called when layout changes */
457
+ onLayoutChange?: (layout: Layout) => void;
458
+ }
459
459
 
460
- // Callback so you can save the layout.
461
- // AllLayouts are keyed by breakpoint.
462
- onLayoutChange: (currentLayout: Layout, allLayouts: {[key: $Keys<breakpoints>]: Layout}) => void,
460
+ interface UseGridLayoutResult {
461
+ /** Current layout */
462
+ layout: Layout;
463
+ /** Set layout directly */
464
+ setLayout: (layout: Layout) => void;
465
+ /** Current drag state (activeDrag, oldDragItem, oldLayout) */
466
+ dragState: DragState;
467
+ /** Current resize state (resizing, oldResizeItem, oldLayout) */
468
+ resizeState: ResizeState;
469
+ /** Current drop state (droppingDOMNode, droppingPosition) */
470
+ dropState: DropState;
471
+ /** Start dragging an item */
472
+ onDragStart: (itemId: string, x: number, y: number) => LayoutItem | null;
473
+ /** Update drag position */
474
+ onDrag: (itemId: string, x: number, y: number) => void;
475
+ /** Stop dragging */
476
+ onDragStop: (itemId: string, x: number, y: number) => void;
477
+ /** Start resizing an item */
478
+ onResizeStart: (itemId: string) => LayoutItem | null;
479
+ /** Update resize dimensions */
480
+ onResize: (
481
+ itemId: string,
482
+ w: number,
483
+ h: number,
484
+ x?: number,
485
+ y?: number
486
+ ) => void;
487
+ /** Stop resizing */
488
+ onResizeStop: (itemId: string, w: number, h: number) => void;
489
+ /** Handle external drag over */
490
+ onDropDragOver: (
491
+ droppingItem: LayoutItem,
492
+ position: DroppingPosition
493
+ ) => void;
494
+ /** Handle external drag leave */
495
+ onDropDragLeave: () => void;
496
+ /** Complete external drop */
497
+ onDrop: (droppingItem: LayoutItem) => void;
498
+ /** Container height in grid rows */
499
+ containerHeight: number;
500
+ /** Whether any drag/resize/drop is active */
501
+ isInteracting: boolean;
502
+ /** The compactor being used */
503
+ compactor: Compactor;
504
+ }
505
+ ```
463
506
 
464
- // Callback when the width changes, so you can modify the layout as needed.
465
- onWidthChange: (containerWidth: number, margin: [number, number], cols: number, containerPadding: [number, number]) => void;
507
+ ### useResponsiveLayout
508
+
509
+ Manages responsive breakpoints and generates layouts for different screen sizes. Use this when building a custom responsive grid.
510
+
511
+ **Why use it instead of the Responsive component?**
512
+
513
+ - Direct access to current breakpoint
514
+ - Control over layout generation for new breakpoints
515
+ - Can update layouts for specific breakpoints
516
+ - Build custom breakpoint UIs
517
+
518
+ ```tsx
519
+ import { useContainerWidth, useResponsiveLayout } from "react-grid-layout";
520
+
521
+ function CustomResponsiveGrid() {
522
+ const { width, containerRef, mounted } = useContainerWidth();
523
+
524
+ const {
525
+ layout, // Current layout for active breakpoint
526
+ layouts, // All layouts by breakpoint
527
+ breakpoint, // Current active breakpoint ('lg', 'md', etc.)
528
+ cols, // Column count for current breakpoint
529
+ setLayoutForBreakpoint,
530
+ setLayouts,
531
+ sortedBreakpoints
532
+ } = useResponsiveLayout({
533
+ width,
534
+ breakpoints: { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 },
535
+ cols: { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 },
536
+ layouts: {
537
+ lg: [{ i: "1", x: 0, y: 0, w: 2, h: 2 }],
538
+ md: [{ i: "1", x: 0, y: 0, w: 3, h: 2 }]
539
+ },
540
+ compactType: "vertical",
541
+ onBreakpointChange: (bp, cols) =>
542
+ console.log(`Now at ${bp} (${cols} cols)`),
543
+ onLayoutChange: (layout, allLayouts) => saveToServer(allLayouts)
544
+ });
545
+
546
+ // Show current breakpoint in UI
547
+ return (
548
+ <div ref={containerRef}>
549
+ <div>
550
+ Current breakpoint: {breakpoint} ({cols} columns)
551
+ </div>
552
+ {mounted && (
553
+ <GridLayout width={width} cols={cols} layout={layout}>
554
+ {/* children */}
555
+ </GridLayout>
556
+ )}
557
+ </div>
558
+ );
559
+ }
560
+ ```
561
+
562
+ **Type Definitions:**
563
+
564
+ ```ts
565
+ interface UseResponsiveLayoutOptions<B extends string = DefaultBreakpoints> {
566
+ /** Current container width */
567
+ width: number;
568
+ /** Breakpoint definitions (name → min-width). Default: {lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0} */
569
+ breakpoints?: Record<B, number>;
570
+ /** Column counts per breakpoint. Default: {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2} */
571
+ cols?: Record<B, number>;
572
+ /** Layouts for each breakpoint */
573
+ layouts?: Partial<Record<B, Layout>>;
574
+ /** Compaction type */
575
+ compactType?: "vertical" | "horizontal" | null;
576
+ /** Called when breakpoint changes */
577
+ onBreakpointChange?: (newBreakpoint: B, cols: number) => void;
578
+ /** Called when layout changes */
579
+ onLayoutChange?: (layout: Layout, layouts: Record<B, Layout>) => void;
580
+ /** Called when width changes */
581
+ onWidthChange?: (
582
+ width: number,
583
+ margin: [number, number],
584
+ cols: number,
585
+ padding: [number, number] | null
586
+ ) => void;
587
+ }
588
+
589
+ interface UseResponsiveLayoutResult<B extends string = DefaultBreakpoints> {
590
+ /** Current layout for the active breakpoint */
591
+ layout: Layout;
592
+ /** All layouts by breakpoint */
593
+ layouts: Partial<Record<B, Layout>>;
594
+ /** Current active breakpoint */
595
+ breakpoint: B;
596
+ /** Column count for the current breakpoint */
597
+ cols: number;
598
+ /** Update layout for a specific breakpoint */
599
+ setLayoutForBreakpoint: (breakpoint: B, layout: Layout) => void;
600
+ /** Update all layouts */
601
+ setLayouts: (layouts: Partial<Record<B, Layout>>) => void;
602
+ /** Sorted array of breakpoint names (smallest to largest) */
603
+ sortedBreakpoints: B[];
604
+ }
466
605
 
606
+ type DefaultBreakpoints = "lg" | "md" | "sm" | "xs" | "xxs";
467
607
  ```
468
608
 
469
- ### Grid Item Props
609
+ ## API Reference
610
+
611
+ ### ReactGridLayout Props
612
+
613
+ The v2 API uses composable configuration interfaces for cleaner prop organization:
614
+
615
+ ```ts
616
+ interface ReactGridLayoutProps {
617
+ // Required
618
+ children: React.ReactNode;
619
+ width: number; // Container width in pixels
620
+
621
+ // Configuration interfaces (see below for details)
622
+ gridConfig?: Partial<GridConfig>; // Grid measurement settings
623
+ dragConfig?: Partial<DragConfig>; // Drag behavior settings
624
+ resizeConfig?: Partial<ResizeConfig>; // Resize behavior settings
625
+ dropConfig?: Partial<DropConfig>; // External drop settings
626
+ positionStrategy?: PositionStrategy; // CSS positioning strategy
627
+ compactor?: Compactor; // Layout compaction strategy
628
+
629
+ // Layout data
630
+ layout?: Layout; // Layout definition
631
+ droppingItem?: LayoutItem; // Item configuration when dropping from outside
632
+
633
+ // Container
634
+ autoSize?: boolean; // Auto-size container height (default: true)
635
+ className?: string;
636
+ style?: React.CSSProperties;
637
+ innerRef?: React.Ref<HTMLDivElement>;
638
+
639
+ // Callbacks
640
+ onLayoutChange?: (layout: Layout) => void;
641
+ onDragStart?: EventCallback;
642
+ onDrag?: EventCallback;
643
+ onDragStop?: EventCallback;
644
+ onResizeStart?: EventCallback;
645
+ onResize?: EventCallback;
646
+ onResizeStop?: EventCallback;
647
+ onDrop?: (layout: Layout, item: LayoutItem | undefined, e: Event) => void;
648
+ onDropDragOver?: (e: DragEvent) => { w?: number; h?: number } | false | void;
649
+ }
650
+ ```
651
+
652
+ ### GridConfig
470
653
 
471
- RGL supports the following properties on grid items or layout items. When initializing a grid,
472
- build a layout array (as in the first example above), or attach this object as the `data-grid` property
473
- to each of your child elements (as in the second example).
654
+ Grid measurement configuration:
655
+
656
+ ```ts
657
+ interface GridConfig {
658
+ cols: number; // Number of columns (default: 12)
659
+ rowHeight: number; // Row height in pixels (default: 150)
660
+ margin: [number, number]; // [x, y] margin between items (default: [10, 10])
661
+ containerPadding: [number, number] | null; // Container padding (default: null, uses margin)
662
+ maxRows: number; // Maximum rows (default: Infinity)
663
+ }
664
+ ```
474
665
 
475
- If `data-grid` is provided on an item, it will take precedence over an item in the `layout` with the same key (`i`).
666
+ ### DragConfig
476
667
 
477
- Note that if a grid item is provided but incomplete (missing one of `x, y, w, or h`), an error
478
- will be thrown so you can correct your layout.
668
+ Drag behavior configuration:
479
669
 
480
- If no properties are provided for a grid item, one will be generated with a width and height of `1`.
670
+ ```ts
671
+ interface DragConfig {
672
+ enabled: boolean; // Enable dragging (default: true)
673
+ bounded: boolean; // Keep items within container (default: false)
674
+ handle?: string; // CSS selector for drag handle
675
+ cancel?: string; // CSS selector to cancel dragging
676
+ threshold: number; // Pixels to move before drag starts (default: 3)
677
+ }
678
+ ```
481
679
 
482
- You can set minimums and maximums for each dimension. This is for resizing; it of course has no effect if resizing
483
- is disabled. Errors will be thrown if your mins and maxes overlap incorrectly, or your initial dimensions
484
- are out of range.
680
+ ### ResizeConfig
485
681
 
486
- Any `<GridItem>` properties defined directly will take precedence over globally-set options. For
487
- example, if the layout has the property `isDraggable: false`, but the grid item has the prop `isDraggable: true`, the item
488
- will be draggable, even if the item is marked `static: true`.
682
+ Resize behavior configuration:
489
683
 
490
- ```js
491
- {
492
-
493
- // A string corresponding to the component key
494
- i: string,
495
-
496
- // These are all in grid units, not pixels
497
- x: number,
498
- y: number,
499
- w: number,
500
- h: number,
501
- minW: ?number = 0,
502
- maxW: ?number = Infinity,
503
- minH: ?number = 0,
504
- maxH: ?number = Infinity,
505
-
506
- // If true, equal to `isDraggable: false, isResizable: false`.
507
- static: ?boolean = false,
508
- // If false, will not be draggable. Overrides `static`.
509
- isDraggable: ?boolean = true,
510
- // If false, will not be resizable. Overrides `static`.
511
- isResizable: ?boolean = true,
512
- // By default, a handle is only shown on the bottom-right (southeast) corner.
513
- // As of RGL >= 1.4.0, resizing on any corner works just fine!
514
- resizeHandles?: ?Array<'s' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne'> = ['se']
515
- // If true and draggable, item will be moved only within grid.
516
- isBounded: ?boolean = false
684
+ ```ts
685
+ interface ResizeConfig {
686
+ enabled: boolean; // Enable resizing (default: true)
687
+ handles: ResizeHandleAxis[]; // Handle positions (default: ['se'])
688
+ handleComponent?: React.ReactNode | ((axis, ref) => React.ReactNode);
517
689
  }
518
690
  ```
519
691
 
520
- ### Grid Item Heights and Widths
692
+ ### DropConfig
521
693
 
522
- Grid item widths are based on container and number of columns. The size of a grid unit's height is based on `rowHeight`.
694
+ External drop configuration:
523
695
 
524
- Note that an item that has `h=2` is _not exactly twice as tall as one with `h=1` unless you have no `margin`_!
696
+ ```ts
697
+ interface DropConfig {
698
+ enabled: boolean; // Allow external drops (default: false)
699
+ defaultItem: { w: number; h: number }; // Default size (default: { w: 1, h: 1 })
700
+ onDragOver?: (e: DragEvent) => { w?: number; h?: number } | false | void;
701
+ }
702
+ ```
525
703
 
526
- In order for the grid to not be ragged, when an item spans grid units, it must also span margins. So you must add the height or width or the margin you are spanning for each unit. So actual pixel height is `(rowHeight * h) + (marginH * (h - 1)`.
704
+ ### PositionStrategy
527
705
 
528
- For example, with `rowHeight=30`, `margin=[10,10]` and a unit with height 4, the calculation is `(30 * 4) + (10 * 3)`
706
+ CSS positioning strategy. Built-in options:
529
707
 
530
- ![margin](margin.png)
708
+ ```ts
709
+ import {
710
+ transformStrategy, // Default: use CSS transforms
711
+ absoluteStrategy, // Use top/left positioning
712
+ createScaledStrategy // For scaled containers
713
+ } from "react-grid-layout/core";
531
714
 
532
- If this is a problem for you, set `margin=[0,0]` and handle visual spacing between your elements inside the elements' content.
715
+ // Example: scaled container
716
+ <div style={{ transform: 'scale(0.5)' }}>
717
+ <ReactGridLayout positionStrategy={createScaledStrategy(0.5)} ... />
718
+ </div>
719
+ ```
533
720
 
534
- ### Performance
721
+ ### Compactor
535
722
 
536
- `<ReactGridLayout>` has [an optimized `shouldComponentUpdate` implementation](lib/ReactGridLayout.jsx), but it relies on the user memoizing the `children` array:
723
+ Layout compaction strategy. Built-in options:
537
724
 
538
- ```js
539
- // lib/ReactGridLayout.jsx
540
- // ...
541
- shouldComponentUpdate(nextProps: Props, nextState: State) {
542
- return (
543
- // NOTE: this is almost always unequal. Therefore the only way to get better performance
544
- // from SCU is if the user intentionally memoizes children. If they do, and they can
545
- // handle changes properly, performance will increase.
546
- this.props.children !== nextProps.children ||
547
- !fastRGLPropsEqual(this.props, nextProps, isEqual) ||
548
- !isEqual(this.state.activeDrag, nextState.activeDrag)
549
- );
725
+ ```ts
726
+ import {
727
+ verticalCompactor, // Default: compact items upward
728
+ horizontalCompactor, // Compact items leftward
729
+ noCompactor, // No compaction (free positioning)
730
+ getCompactor // Factory: getCompactor('vertical', allowOverlap, preventCollision)
731
+ } from "react-grid-layout/core";
732
+ ```
733
+
734
+ ### ResponsiveGridLayout Props
735
+
736
+ Extends `GridLayoutProps` with responsive-specific props:
737
+
738
+ ```ts
739
+ interface ResponsiveGridLayoutProps<B extends string = string> {
740
+ // Responsive configuration
741
+ breakpoint?: B; // Current breakpoint (auto-detected)
742
+ breakpoints?: Record<B, number>; // Breakpoint definitions (default: {lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0})
743
+ cols?: Record<B, number>; // Columns per breakpoint (default: {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2})
744
+ layouts?: Record<B, Layout>; // Layouts per breakpoint
745
+
746
+ // Can be fixed or per-breakpoint
747
+ margin?: [number, number] | Partial<Record<B, [number, number]>>;
748
+ containerPadding?:
749
+ | [number, number]
750
+ | Partial<Record<B, [number, number] | null>>
751
+ | null;
752
+
753
+ // Callbacks
754
+ onBreakpointChange?: (newBreakpoint: B, cols: number) => void;
755
+ onLayoutChange?: (layout: Layout, layouts: Record<B, Layout>) => void;
756
+ onWidthChange?: (
757
+ width: number,
758
+ margin: [number, number],
759
+ cols: number,
760
+ padding: [number, number] | null
761
+ ) => void;
550
762
  }
551
- // ...
552
763
  ```
553
764
 
554
- If you memoize your children, you can take advantage of this, and reap faster rerenders. For example:
765
+ ### Layout Item
766
+
767
+ ```ts
768
+ interface LayoutItem {
769
+ i: string; // Unique identifier (must match child key)
770
+ x: number; // X position in grid units
771
+ y: number; // Y position in grid units
772
+ w: number; // Width in grid units
773
+ h: number; // Height in grid units
774
+ minW?: number; // Minimum width (default: 0)
775
+ maxW?: number; // Maximum width (default: Infinity)
776
+ minH?: number; // Minimum height (default: 0)
777
+ maxH?: number; // Maximum height (default: Infinity)
778
+ static?: boolean; // If true, not draggable or resizable
779
+ isDraggable?: boolean; // Override grid isDraggable
780
+ isResizable?: boolean; // Override grid isResizable
781
+ isBounded?: boolean; // Override grid isBounded
782
+ resizeHandles?: Array<"s" | "w" | "e" | "n" | "sw" | "nw" | "se" | "ne">;
783
+ }
784
+ ```
555
785
 
556
- ```js
557
- function MyGrid(props) {
558
- const children = React.useMemo(() => {
559
- return new Array(props.count).fill(undefined).map((val, idx) => {
560
- return <div key={idx} data-grid={{ x: idx, y: 1, w: 1, h: 1 }} />;
561
- });
562
- }, [props.count]);
563
- return <ReactGridLayout cols={12}>{children}</ReactGridLayout>;
786
+ ### Core Utilities
787
+
788
+ Import pure layout functions from `react-grid-layout/core`:
789
+
790
+ ```ts
791
+ import {
792
+ compact,
793
+ moveElement,
794
+ collides,
795
+ getFirstCollision,
796
+ validateLayout
797
+ // ... and more
798
+ } from "react-grid-layout/core";
799
+ ```
800
+
801
+ ## Extending: Custom Compactors & Position Strategies
802
+
803
+ ### Creating a Custom Compactor
804
+
805
+ Compactors control how items are arranged after drag/resize. Create your own for custom layouts like masonry, gravity, or shelf-packing.
806
+
807
+ **The Compactor Interface:**
808
+
809
+ ```ts
810
+ interface Compactor {
811
+ /** Identifies the compaction type */
812
+ type: "vertical" | "horizontal" | null | string;
813
+
814
+ /** Whether this compactor allows overlapping items */
815
+ allowOverlap: boolean;
816
+
817
+ /** Prevent items from moving when another item is dragged into them */
818
+ preventCollision?: boolean;
819
+
820
+ /**
821
+ * Compact the entire layout.
822
+ * Called after any layout change to fill gaps.
823
+ *
824
+ * @param layout - Array of layout items (clone before mutating!)
825
+ * @param cols - Number of grid columns
826
+ * @returns New compacted layout
827
+ */
828
+ compact(layout: Layout, cols: number): Layout;
829
+
830
+ /**
831
+ * Handle moving an item.
832
+ * Called during drag to preview the new position.
833
+ *
834
+ * @param layout - Current layout
835
+ * @param item - Item being moved
836
+ * @param x - New X position in grid units
837
+ * @param y - New Y position in grid units
838
+ * @param cols - Number of grid columns
839
+ * @returns Updated layout with item at new position
840
+ */
841
+ onMove(
842
+ layout: Layout,
843
+ item: LayoutItem,
844
+ x: number,
845
+ y: number,
846
+ cols: number
847
+ ): Layout;
564
848
  }
565
849
  ```
566
850
 
567
- Because the `children` prop doesn't change between rerenders, updates to `<MyGrid>` won't result in new renders, improving performance.
851
+ **Example: Gravity Compactor (items fall to bottom)**
852
+
853
+ ```ts
854
+ import { cloneLayout, cloneLayoutItem, getStatics, bottom } from "react-grid-layout/core";
855
+
856
+ const gravityCompactor: Compactor = {
857
+ type: "gravity",
858
+ allowOverlap: false,
859
+
860
+ compact(layout, cols) {
861
+ const statics = getStatics(layout);
862
+ const maxY = 100; // arbitrary max height
863
+ const out = [];
864
+
865
+ // Sort by Y descending (process bottom items first)
866
+ const sorted = [...layout].sort((a, b) => b.y - a.y);
867
+
868
+ for (const item of sorted) {
869
+ const l = cloneLayoutItem(item);
870
+
871
+ if (!l.static) {
872
+ // Move down as far as possible
873
+ while (l.y < maxY && !collides(l, statics)) {
874
+ l.y++;
875
+ }
876
+ l.y--; // Back up one
877
+ }
878
+
879
+ out.push(l);
880
+ }
881
+
882
+ return out;
883
+ },
884
+
885
+ onMove(layout, item, x, y, cols) {
886
+ const newLayout = cloneLayout(layout);
887
+ const movedItem = newLayout.find(l => l.i === item.i);
888
+ if (movedItem) {
889
+ movedItem.x = x;
890
+ movedItem.y = y;
891
+ movedItem.moved = true;
892
+ }
893
+ return newLayout;
894
+ }
895
+ };
568
896
 
569
- ### React Hooks Performance
897
+ // Usage
898
+ <GridLayout compactor={gravityCompactor} />
899
+ ```
570
900
 
571
- Using hooks to save your layout state on change will cause the layouts to re-render as the ResponsiveGridLayout will change it's value on every render.
572
- To avoid this you should wrap your WidthProvider in a useMemo:
901
+ **Example: Single Row Compactor (horizontal shelf)**
902
+
903
+ ```ts
904
+ const singleRowCompactor: Compactor = {
905
+ type: "shelf",
906
+ allowOverlap: false,
907
+
908
+ compact(layout, cols) {
909
+ let x = 0;
910
+ const out = [];
911
+
912
+ // Sort by original X position
913
+ const sorted = [...layout].sort((a, b) => a.x - b.x);
914
+
915
+ for (const item of sorted) {
916
+ const l = cloneLayoutItem(item);
917
+ if (!l.static) {
918
+ l.x = x;
919
+ l.y = 0; // All items on row 0
920
+ x += l.w;
921
+
922
+ // Wrap to next row if overflow
923
+ if (x > cols) {
924
+ l.x = 0;
925
+ x = l.w;
926
+ }
927
+ }
928
+ out.push(l);
929
+ }
930
+
931
+ return out;
932
+ },
933
+
934
+ onMove(layout, item, x, y, cols) {
935
+ // Same as default - just update position
936
+ const newLayout = cloneLayout(layout);
937
+ const movedItem = newLayout.find(l => l.i === item.i);
938
+ if (movedItem) {
939
+ movedItem.x = x;
940
+ movedItem.y = 0; // Force row 0
941
+ movedItem.moved = true;
942
+ }
943
+ return newLayout;
944
+ }
945
+ };
946
+ ```
573
947
 
574
- ```js
575
- const ResponsiveReactGridLayout = useMemo(() => WidthProvider(Responsive), []);
948
+ **Using Helper Functions:**
949
+
950
+ The core module exports helpers for building compactors:
951
+
952
+ ```ts
953
+ import {
954
+ resolveCompactionCollision, // Move items to resolve overlaps
955
+ compactItemVertical, // Compact one item upward
956
+ compactItemHorizontal, // Compact one item leftward
957
+ getFirstCollision, // Find first collision
958
+ collides, // Check if two items collide
959
+ getStatics, // Get static items from layout
960
+ cloneLayout, // Clone layout array
961
+ cloneLayoutItem // Clone single item
962
+ } from "react-grid-layout/core";
576
963
  ```
577
964
 
578
- ### Custom Child Components and Draggable Handles
965
+ ### Creating a Custom Position Strategy
966
+
967
+ Position strategies control how items are positioned via CSS. Create custom strategies for special transform handling.
968
+
969
+ **The PositionStrategy Interface:**
970
+
971
+ ```ts
972
+ interface PositionStrategy {
973
+ /** Type identifier */
974
+ type: "transform" | "absolute" | string;
975
+
976
+ /** Scale factor for coordinate calculations */
977
+ scale: number;
978
+
979
+ /**
980
+ * Generate CSS styles for positioning an item.
981
+ *
982
+ * @param pos - Position with top, left, width, height in pixels
983
+ * @returns CSS properties object
984
+ */
985
+ calcStyle(pos: Position): React.CSSProperties;
986
+
987
+ /**
988
+ * Calculate drag position from mouse coordinates.
989
+ * Used during drag to convert screen coords to grid coords.
990
+ *
991
+ * @param clientX - Mouse X position
992
+ * @param clientY - Mouse Y position
993
+ * @param offsetX - Offset from item left edge
994
+ * @param offsetY - Offset from item top edge
995
+ * @returns Calculated left/top position
996
+ */
997
+ calcDragPosition(
998
+ clientX: number,
999
+ clientY: number,
1000
+ offsetX: number,
1001
+ offsetY: number
1002
+ ): { left: number; top: number };
1003
+ }
1004
+ ```
579
1005
 
580
- If you use React Components as grid children, they need to do a few things:
1006
+ **Example: Rotated Container Strategy**
1007
+
1008
+ ```ts
1009
+ const createRotatedStrategy = (angleDegrees: number): PositionStrategy => {
1010
+ const angleRad = (angleDegrees * Math.PI) / 180;
1011
+ const cos = Math.cos(angleRad);
1012
+ const sin = Math.sin(angleRad);
1013
+
1014
+ return {
1015
+ type: "rotated",
1016
+ scale: 1,
1017
+
1018
+ calcStyle(pos) {
1019
+ // Apply rotation to position
1020
+ const rotatedX = pos.left * cos - pos.top * sin;
1021
+ const rotatedY = pos.left * sin + pos.top * cos;
1022
+
1023
+ return {
1024
+ transform: `translate(${rotatedX}px, ${rotatedY}px)`,
1025
+ width: `${pos.width}px`,
1026
+ height: `${pos.height}px`,
1027
+ position: "absolute"
1028
+ };
1029
+ },
1030
+
1031
+ calcDragPosition(clientX, clientY, offsetX, offsetY) {
1032
+ // Reverse the rotation for drag calculations
1033
+ const x = clientX - offsetX;
1034
+ const y = clientY - offsetY;
1035
+
1036
+ return {
1037
+ left: x * cos + y * sin,
1038
+ top: -x * sin + y * cos
1039
+ };
1040
+ }
1041
+ };
1042
+ };
1043
+
1044
+ // Usage: grid inside a rotated container
1045
+ <div style={{ transform: 'rotate(45deg)' }}>
1046
+ <GridLayout positionStrategy={createRotatedStrategy(45)} />
1047
+ </div>
1048
+ ```
581
1049
 
582
- 1. Forward refs to an underlying DOM node, and
583
- 2. Forward `style`,`className`, `onMouseDown`, `onMouseUp` and `onTouchEnd` to that same DOM node.
1050
+ **Example: 3D Perspective Strategy**
1051
+
1052
+ ```ts
1053
+ const create3DStrategy = (
1054
+ perspective: number,
1055
+ rotateX: number
1056
+ ): PositionStrategy => ({
1057
+ type: "3d",
1058
+ scale: 1,
1059
+
1060
+ calcStyle(pos) {
1061
+ return {
1062
+ transform: `
1063
+ perspective(${perspective}px)
1064
+ rotateX(${rotateX}deg)
1065
+ translate3d(${pos.left}px, ${pos.top}px, 0)
1066
+ `,
1067
+ width: `${pos.width}px`,
1068
+ height: `${pos.height}px`,
1069
+ position: "absolute",
1070
+ transformStyle: "preserve-3d"
1071
+ };
1072
+ },
1073
+
1074
+ calcDragPosition(clientX, clientY, offsetX, offsetY) {
1075
+ // Adjust for perspective foreshortening
1076
+ const perspectiveFactor = 1 + clientY / perspective;
1077
+ return {
1078
+ left: (clientX - offsetX) / perspectiveFactor,
1079
+ top: (clientY - offsetY) / perspectiveFactor
1080
+ };
1081
+ }
1082
+ });
1083
+ ```
584
1084
 
585
- For example:
1085
+ ## Extras
1086
+
1087
+ 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.
1088
+
1089
+ ### GridBackground
1090
+
1091
+ Renders an SVG grid background that aligns with GridLayout cells. Use this to visualize the grid structure behind your layout.
1092
+
1093
+ > Based on [PR #2175](https://github.com/react-grid-layout/react-grid-layout/pull/2175) by [@nicosayer](https://github.com/nicosayer).
1094
+
1095
+ ```tsx
1096
+ import { GridBackground } from "react-grid-layout/extras";
1097
+ import ReactGridLayout, { useContainerWidth } from "react-grid-layout";
1098
+
1099
+ function MyGrid() {
1100
+ const { width, containerRef, mounted } = useContainerWidth();
586
1101
 
587
- ```js
588
- const CustomGridItemComponent = React.forwardRef(({style, className, onMouseDown, onMouseUp, onTouchEnd, children, ...props}, ref) => {
589
1102
  return (
590
- <div style={{ /* styles */, ...style}} className={className} ref={ref} onMouseDown={onMouseDown} onMouseUp={onMouseUp} onTouchEnd={onTouchEnd}>
591
- {/* Some other content */}
592
- {children} {/* Make sure to include children to add resizable handle */}
1103
+ <div ref={containerRef} style={{ position: "relative" }}>
1104
+ {mounted && (
1105
+ <>
1106
+ <GridBackground
1107
+ width={width}
1108
+ cols={12}
1109
+ rowHeight={30}
1110
+ margin={[10, 10]}
1111
+ rows={10}
1112
+ color="#f0f0f0"
1113
+ borderRadius={4}
1114
+ />
1115
+ <ReactGridLayout
1116
+ width={width}
1117
+ gridConfig={{ cols: 12, rowHeight: 30, margin: [10, 10] }}
1118
+ >
1119
+ {children}
1120
+ </ReactGridLayout>
1121
+ </>
1122
+ )}
593
1123
  </div>
594
1124
  );
595
- })
1125
+ }
1126
+ ```
1127
+
1128
+ **Props:**
1129
+
1130
+ ```ts
1131
+ interface GridBackgroundProps {
1132
+ // Required - must match your GridLayout config
1133
+ width: number; // Container width
1134
+ cols: number; // Number of columns
1135
+ rowHeight: number; // Row height in pixels
1136
+
1137
+ // Optional
1138
+ margin?: [number, number]; // Gap between cells (default: [10, 10])
1139
+ containerPadding?: [number, number] | null; // Container padding (default: uses margin)
1140
+ rows?: number | "auto"; // Number of rows to display (default: 10)
1141
+ height?: number; // Used when rows="auto" to calculate row count
1142
+ color?: string; // Cell background color (default: "#e0e0e0")
1143
+ borderRadius?: number; // Cell border radius (default: 4)
1144
+ className?: string; // Additional CSS class
1145
+ style?: React.CSSProperties; // Additional inline styles
1146
+ }
1147
+ ```
1148
+
1149
+ ### calcGridCellDimensions (Core Utility)
1150
+
1151
+ For building custom grid overlays or backgrounds, use the `calcGridCellDimensions` utility from `react-grid-layout/core`:
1152
+
1153
+ ```ts
1154
+ import { calcGridCellDimensions } from "react-grid-layout/core";
1155
+
1156
+ const dims = calcGridCellDimensions({
1157
+ width: 1200,
1158
+ cols: 12,
1159
+ rowHeight: 30,
1160
+ margin: [10, 10],
1161
+ containerPadding: [20, 20]
1162
+ });
1163
+
1164
+ // dims = {
1165
+ // cellWidth: 88.33, // Width of each cell
1166
+ // cellHeight: 30, // Height of each cell (= rowHeight)
1167
+ // offsetX: 20, // Left padding
1168
+ // offsetY: 20, // Top padding
1169
+ // gapX: 10, // Horizontal gap between cells
1170
+ // gapY: 10, // Vertical gap between cells
1171
+ // cols: 12, // Column count
1172
+ // containerWidth: 1200
1173
+ // }
1174
+ ```
1175
+
1176
+ This is useful for building custom visualizations, snap-to-grid functionality, or integrating with canvas/WebGL renderers.
1177
+
1178
+ ## Performance
1179
+
1180
+ ### Memoize Children
1181
+
1182
+ The grid compares children by reference. Memoize them for better performance:
1183
+
1184
+ ```tsx
1185
+ function MyGrid({ count, width }) {
1186
+ const children = useMemo(() => {
1187
+ return Array.from({ length: count }, (_, i) => (
1188
+ <div
1189
+ key={i}
1190
+ data-grid={{ x: i % 12, y: Math.floor(i / 12), w: 1, h: 1 }}
1191
+ />
1192
+ ));
1193
+ }, [count]);
1194
+
1195
+ return (
1196
+ <ReactGridLayout width={width} gridConfig={{ cols: 12 }}>
1197
+ {children}
1198
+ </ReactGridLayout>
1199
+ );
1200
+ }
596
1201
  ```
597
1202
 
598
- The same is true of custom elements as draggable handles using the `draggableHandle` prop. This is so that
599
- the underlying `react-draggable` library can get a reference to the DOM node underneath, manipulate
600
- positioning via `style`, and set classes.
1203
+ ### Avoid Creating Components in Render (Legacy WidthProvider)
1204
+
1205
+ If using the legacy WidthProvider HOC, don't create the component during render:
1206
+
1207
+ ```tsx
1208
+ import ReactGridLayout, { WidthProvider } from "react-grid-layout/legacy";
1209
+
1210
+ // Bad - creates new component every render
1211
+ function MyGrid() {
1212
+ const GridLayoutWithWidth = WidthProvider(ReactGridLayout);
1213
+ return <GridLayoutWithWidth>...</GridLayoutWithWidth>;
1214
+ }
1215
+
1216
+ // Good - create once outside or with useMemo
1217
+ const GridLayoutWithWidth = WidthProvider(ReactGridLayout);
1218
+
1219
+ function MyGrid() {
1220
+ return <GridLayoutWithWidth>...</GridLayoutWithWidth>;
1221
+ }
1222
+ ```
1223
+
1224
+ With the v2 API, use `useContainerWidth` hook instead to avoid this issue entirely.
1225
+
1226
+ ## Custom Child Components
1227
+
1228
+ Grid children must forward refs and certain props:
1229
+
1230
+ ```tsx
1231
+ const CustomItem = forwardRef<HTMLDivElement, CustomItemProps>(
1232
+ (
1233
+ {
1234
+ style,
1235
+ className,
1236
+ onMouseDown,
1237
+ onMouseUp,
1238
+ onTouchEnd,
1239
+ children,
1240
+ ...props
1241
+ },
1242
+ ref
1243
+ ) => {
1244
+ return (
1245
+ <div
1246
+ ref={ref}
1247
+ style={style}
1248
+ className={className}
1249
+ onMouseDown={onMouseDown}
1250
+ onMouseUp={onMouseUp}
1251
+ onTouchEnd={onTouchEnd}
1252
+ >
1253
+ {children}
1254
+ </div>
1255
+ );
1256
+ }
1257
+ );
1258
+ ```
601
1259
 
602
1260
  ## Contribute
603
1261
 
@@ -605,19 +1263,3 @@ If you have a feature request, please add it as an issue or make a pull request.
605
1263
 
606
1264
  If you have a bug to report, please reproduce the bug in [CodeSandbox](https://codesandbox.io/s/staging-bush-3lvt7?file=/src/ShowcaseLayout.js) to help
607
1265
  us easily isolate it.
608
-
609
- ## TODO List
610
-
611
- - [x] Basic grid layout
612
- - [x] Fluid grid layout
613
- - [x] Grid packing
614
- - [x] Draggable grid items
615
- - [x] Live grid packing while dragging
616
- - [x] Resizable grid items
617
- - [x] Layouts per responsive breakpoint
618
- - [x] Define grid attributes on children themselves (`data-grid` key)
619
- - [x] Static elements
620
- - [x] Persistent id per item for predictable localstorage restores, even when # items changes
621
- - [x] Min/max w/h per item
622
- - [x] Resizable handles on other corners
623
- - [ ] Configurable w/h per breakpoint